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)