Mercurial > vim
comparison src/eval.c @ 17674:06c3e15ad84d v8.1.1834
patch 8.1.1834: cannot use a lambda as a method
commit https://github.com/vim/vim/commit/22a0c0c4ecd23b6c43f79ba9b92899ca0b426e29
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Aug 9 23:25:08 2019 +0200
patch 8.1.1834: cannot use a lambda as a method
Problem: Cannot use a lambda as a method.
Solution: Implement ->{lambda}(). (closes https://github.com/vim/vim/issues/4768)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 09 Aug 2019 23:30:05 +0200 |
parents | da7890e3359b |
children | 117c7795a979 |
comparison
equal
deleted
inserted
replaced
17673:3043c52e08e4 | 17674:06c3e15ad84d |
---|---|
30 static char *e_illvar = N_("E461: Illegal variable name: %s"); | 30 static char *e_illvar = N_("E461: Illegal variable name: %s"); |
31 static char *e_cannot_mod = N_("E995: Cannot modify existing variable"); | 31 static char *e_cannot_mod = N_("E995: Cannot modify existing variable"); |
32 #ifdef FEAT_FLOAT | 32 #ifdef FEAT_FLOAT |
33 static char *e_float_as_string = N_("E806: using Float as a String"); | 33 static char *e_float_as_string = N_("E806: using Float as a String"); |
34 #endif | 34 #endif |
35 static char *e_nowhitespace = N_("E274: No white space allowed before parenthesis"); | |
35 | 36 |
36 #define NAMESPACE_CHAR (char_u *)"abglstvw" | 37 #define NAMESPACE_CHAR (char_u *)"abglstvw" |
37 | 38 |
38 static dictitem_T globvars_var; /* variable used for g: */ | 39 static dictitem_T globvars_var; /* variable used for g: */ |
39 | 40 |
3691 | 3692 |
3692 // Invoke the function. | 3693 // Invoke the function. |
3693 vim_memset(&funcexe, 0, sizeof(funcexe)); | 3694 vim_memset(&funcexe, 0, sizeof(funcexe)); |
3694 funcexe.firstline = curwin->w_cursor.lnum; | 3695 funcexe.firstline = curwin->w_cursor.lnum; |
3695 funcexe.lastline = curwin->w_cursor.lnum; | 3696 funcexe.lastline = curwin->w_cursor.lnum; |
3696 funcexe.doesrange = &len; | |
3697 funcexe.evaluate = evaluate; | 3697 funcexe.evaluate = evaluate; |
3698 funcexe.partial = partial; | 3698 funcexe.partial = partial; |
3699 funcexe.basetv = basetv; | 3699 funcexe.basetv = basetv; |
3700 ret = get_func_tv(s, len, rettv, arg, &funcexe); | 3700 ret = get_func_tv(s, len, rettv, arg, &funcexe); |
3701 } | 3701 } |
4820 | 4820 |
4821 return ret; | 4821 return ret; |
4822 } | 4822 } |
4823 | 4823 |
4824 /* | 4824 /* |
4825 * Call the function referred to in "rettv". | |
4826 */ | |
4827 static int | |
4828 call_func_rettv( | |
4829 char_u **arg, | |
4830 typval_T *rettv, | |
4831 int evaluate, | |
4832 dict_T *selfdict, | |
4833 typval_T *basetv) | |
4834 { | |
4835 partial_T *pt = NULL; | |
4836 funcexe_T funcexe; | |
4837 typval_T functv; | |
4838 char_u *s; | |
4839 int ret; | |
4840 | |
4841 // need to copy the funcref so that we can clear rettv | |
4842 if (evaluate) | |
4843 { | |
4844 functv = *rettv; | |
4845 rettv->v_type = VAR_UNKNOWN; | |
4846 | |
4847 /* Invoke the function. Recursive! */ | |
4848 if (functv.v_type == VAR_PARTIAL) | |
4849 { | |
4850 pt = functv.vval.v_partial; | |
4851 s = partial_name(pt); | |
4852 } | |
4853 else | |
4854 s = functv.vval.v_string; | |
4855 } | |
4856 else | |
4857 s = (char_u *)""; | |
4858 | |
4859 vim_memset(&funcexe, 0, sizeof(funcexe)); | |
4860 funcexe.firstline = curwin->w_cursor.lnum; | |
4861 funcexe.lastline = curwin->w_cursor.lnum; | |
4862 funcexe.evaluate = evaluate; | |
4863 funcexe.partial = pt; | |
4864 funcexe.selfdict = selfdict; | |
4865 funcexe.basetv = basetv; | |
4866 ret = get_func_tv(s, -1, rettv, arg, &funcexe); | |
4867 | |
4868 /* Clear the funcref afterwards, so that deleting it while | |
4869 * evaluating the arguments is possible (see test55). */ | |
4870 if (evaluate) | |
4871 clear_tv(&functv); | |
4872 | |
4873 return ret; | |
4874 } | |
4875 | |
4876 /* | |
4877 * Evaluate "->method()". | |
4878 * "*arg" points to the '-'. | |
4879 * Returns FAIL or OK. "*arg" is advanced to after the ')'. | |
4880 */ | |
4881 static int | |
4882 eval_lambda( | |
4883 char_u **arg, | |
4884 typval_T *rettv, | |
4885 int evaluate, | |
4886 int verbose) /* give error messages */ | |
4887 { | |
4888 typval_T base = *rettv; | |
4889 int ret; | |
4890 | |
4891 // Skip over the ->. | |
4892 *arg += 2; | |
4893 rettv->v_type = VAR_UNKNOWN; | |
4894 | |
4895 ret = get_lambda_tv(arg, rettv, evaluate); | |
4896 if (ret == NOTDONE) | |
4897 return FAIL; | |
4898 else if (**arg != '(') | |
4899 { | |
4900 if (verbose) | |
4901 { | |
4902 if (*skipwhite(*arg) == '(') | |
4903 semsg(_(e_nowhitespace)); | |
4904 else | |
4905 semsg(_(e_missingparen), "lambda"); | |
4906 } | |
4907 clear_tv(rettv); | |
4908 return FAIL; | |
4909 } | |
4910 return call_func_rettv(arg, rettv, evaluate, NULL, &base); | |
4911 } | |
4912 | |
4913 /* | |
4825 * Evaluate "->method()". | 4914 * Evaluate "->method()". |
4826 * "*arg" points to the '-'. | 4915 * "*arg" points to the '-'. |
4827 * Returns FAIL or OK. "*arg" is advanced to after the ')'. | 4916 * Returns FAIL or OK. "*arg" is advanced to after the ')'. |
4828 */ | 4917 */ |
4829 static int | 4918 static int |
4863 ret = FAIL; | 4952 ret = FAIL; |
4864 } | 4953 } |
4865 else if (VIM_ISWHITE((*arg)[-1])) | 4954 else if (VIM_ISWHITE((*arg)[-1])) |
4866 { | 4955 { |
4867 if (verbose) | 4956 if (verbose) |
4868 semsg(_("E274: No white space allowed before parenthesis")); | 4957 semsg(_(e_nowhitespace)); |
4869 ret = FAIL; | 4958 ret = FAIL; |
4870 } | 4959 } |
4871 else | 4960 else |
4872 ret = eval_func(arg, name, len, rettv, evaluate, &base); | 4961 ret = eval_func(arg, name, len, rettv, evaluate, &base); |
4873 } | 4962 } |
4874 | 4963 |
4875 /* Clear the funcref afterwards, so that deleting it while | 4964 // Clear the funcref afterwards, so that deleting it while |
4876 * evaluating the arguments is possible (see test55). */ | 4965 // evaluating the arguments is possible (see test55). |
4877 if (evaluate) | 4966 if (evaluate) |
4878 clear_tv(&base); | 4967 clear_tv(&base); |
4879 | 4968 |
4880 return ret; | 4969 return ret; |
4881 } | 4970 } |
7453 int evaluate, /* do more than finding the end */ | 7542 int evaluate, /* do more than finding the end */ |
7454 int verbose) /* give error messages */ | 7543 int verbose) /* give error messages */ |
7455 { | 7544 { |
7456 int ret = OK; | 7545 int ret = OK; |
7457 dict_T *selfdict = NULL; | 7546 dict_T *selfdict = NULL; |
7458 char_u *s; | |
7459 typval_T functv; | |
7460 | 7547 |
7461 // "." is ".name" lookup when we found a dict or when evaluating and | 7548 // "." is ".name" lookup when we found a dict or when evaluating and |
7462 // scriptversion is at least 2, where string concatenation is "..". | 7549 // scriptversion is at least 2, where string concatenation is "..". |
7463 while (ret == OK | 7550 while (ret == OK |
7464 && (((**arg == '[' | 7551 && (((**arg == '[' |
7471 && !VIM_ISWHITE(*(*arg - 1))) | 7558 && !VIM_ISWHITE(*(*arg - 1))) |
7472 || (**arg == '-' && (*arg)[1] == '>'))) | 7559 || (**arg == '-' && (*arg)[1] == '>'))) |
7473 { | 7560 { |
7474 if (**arg == '(') | 7561 if (**arg == '(') |
7475 { | 7562 { |
7476 partial_T *pt = NULL; | 7563 ret = call_func_rettv(arg, rettv, evaluate, selfdict, NULL); |
7477 funcexe_T funcexe; | 7564 |
7478 | 7565 // Stop the expression evaluation when immediately aborting on |
7479 /* need to copy the funcref so that we can clear rettv */ | 7566 // error, or when an interrupt occurred or an exception was thrown |
7480 if (evaluate) | 7567 // but not caught. |
7481 { | |
7482 functv = *rettv; | |
7483 rettv->v_type = VAR_UNKNOWN; | |
7484 | |
7485 /* Invoke the function. Recursive! */ | |
7486 if (functv.v_type == VAR_PARTIAL) | |
7487 { | |
7488 pt = functv.vval.v_partial; | |
7489 s = partial_name(pt); | |
7490 } | |
7491 else | |
7492 s = functv.vval.v_string; | |
7493 } | |
7494 else | |
7495 s = (char_u *)""; | |
7496 | |
7497 vim_memset(&funcexe, 0, sizeof(funcexe)); | |
7498 funcexe.firstline = curwin->w_cursor.lnum; | |
7499 funcexe.lastline = curwin->w_cursor.lnum; | |
7500 funcexe.evaluate = evaluate; | |
7501 funcexe.partial = pt; | |
7502 funcexe.selfdict = selfdict; | |
7503 ret = get_func_tv(s, -1, rettv, arg, &funcexe); | |
7504 | |
7505 /* Clear the funcref afterwards, so that deleting it while | |
7506 * evaluating the arguments is possible (see test55). */ | |
7507 if (evaluate) | |
7508 clear_tv(&functv); | |
7509 | |
7510 /* Stop the expression evaluation when immediately aborting on | |
7511 * error, or when an interrupt occurred or an exception was thrown | |
7512 * but not caught. */ | |
7513 if (aborting()) | 7568 if (aborting()) |
7514 { | 7569 { |
7515 if (ret == OK) | 7570 if (ret == OK) |
7516 clear_tv(rettv); | 7571 clear_tv(rettv); |
7517 ret = FAIL; | 7572 ret = FAIL; |
7519 dict_unref(selfdict); | 7574 dict_unref(selfdict); |
7520 selfdict = NULL; | 7575 selfdict = NULL; |
7521 } | 7576 } |
7522 else if (**arg == '-') | 7577 else if (**arg == '-') |
7523 { | 7578 { |
7524 if (eval_method(arg, rettv, evaluate, verbose) == FAIL) | 7579 if ((*arg)[2] == '{') |
7525 { | 7580 // expr->{lambda}() |
7526 clear_tv(rettv); | 7581 ret = eval_lambda(arg, rettv, evaluate, verbose); |
7527 ret = FAIL; | 7582 else |
7528 } | 7583 // expr->name() |
7584 ret = eval_method(arg, rettv, evaluate, verbose); | |
7529 } | 7585 } |
7530 else /* **arg == '[' || **arg == '.' */ | 7586 else /* **arg == '[' || **arg == '.' */ |
7531 { | 7587 { |
7532 dict_unref(selfdict); | 7588 dict_unref(selfdict); |
7533 if (rettv->v_type == VAR_DICT) | 7589 if (rettv->v_type == VAR_DICT) |