comparison src/eval.c @ 17612:e259d11e2900 v8.1.1803

patch 8.1.1803: all builtin functions are global commit https://github.com/vim/vim/commit/ac92e25a33c37ec5becbfffeccda136c73b761ac Author: Bram Moolenaar <Bram@vim.org> Date: Sat Aug 3 21:58:38 2019 +0200 patch 8.1.1803: all builtin functions are global Problem: All builtin functions are global. Solution: Add the method call operator ->. Implemented for a limited number of functions.
author Bram Moolenaar <Bram@vim.org>
date Sat, 03 Aug 2019 22:00:07 +0200
parents ff097edaae89
children 9ffec4eb8d33
comparison
equal deleted inserted replaced
17611:b9a3d542a042 17612:e259d11e2900
4410 * ! in front logical NOT 4410 * ! in front logical NOT
4411 * - in front unary minus 4411 * - in front unary minus
4412 * + in front unary plus (ignored) 4412 * + in front unary plus (ignored)
4413 * trailing [] subscript in String or List 4413 * trailing [] subscript in String or List
4414 * trailing .name entry in Dictionary 4414 * trailing .name entry in Dictionary
4415 * trailing ->name() method call
4415 * 4416 *
4416 * "arg" must point to the first non-white of the expression. 4417 * "arg" must point to the first non-white of the expression.
4417 * "arg" is advanced to the next non-white after the recognized expression. 4418 * "arg" is advanced to the next non-white after the recognized expression.
4418 * 4419 *
4419 * Return OK or FAIL. 4420 * Return OK or FAIL.
4688 else 4689 else
4689 { 4690 {
4690 funcexe_T funcexe; 4691 funcexe_T funcexe;
4691 4692
4692 // Invoke the function. 4693 // Invoke the function.
4693 funcexe.argv_func = NULL; 4694 vim_memset(&funcexe, 0, sizeof(funcexe));
4694 funcexe.firstline = curwin->w_cursor.lnum; 4695 funcexe.firstline = curwin->w_cursor.lnum;
4695 funcexe.lastline = curwin->w_cursor.lnum; 4696 funcexe.lastline = curwin->w_cursor.lnum;
4696 funcexe.doesrange = &len; 4697 funcexe.doesrange = &len;
4697 funcexe.evaluate = evaluate; 4698 funcexe.evaluate = evaluate;
4698 funcexe.partial = partial; 4699 funcexe.partial = partial;
4699 funcexe.selfdict = NULL;
4700 ret = get_func_tv(s, len, rettv, arg, &funcexe); 4700 ret = get_func_tv(s, len, rettv, arg, &funcexe);
4701 } 4701 }
4702 vim_free(s); 4702 vim_free(s);
4703 4703
4704 /* If evaluate is FALSE rettv->v_type was not set in 4704 /* If evaluate is FALSE rettv->v_type was not set in
4796 rettv->vval.v_number = val; 4796 rettv->vval.v_number = val;
4797 } 4797 }
4798 } 4798 }
4799 } 4799 }
4800 4800
4801 return ret;
4802 }
4803
4804 /*
4805 * Evaluate "->method()".
4806 * "*arg" points to the '-'.
4807 * Returns FAIL or OK. "*arg" is advanced to after the ')'.
4808 */
4809 static int
4810 eval_method(
4811 char_u **arg,
4812 typval_T *rettv,
4813 int evaluate,
4814 int verbose) /* give error messages */
4815 {
4816 char_u *name;
4817 long len;
4818 funcexe_T funcexe;
4819 int ret = OK;
4820 typval_T base = *rettv;
4821
4822 // Skip over the ->.
4823 *arg += 2;
4824
4825 // Locate the method name.
4826 name = *arg;
4827 for (len = 0; ASCII_ISALNUM(name[len]) || name[len] == '_'; ++len)
4828 ;
4829 if (len == 0)
4830 {
4831 if (verbose)
4832 emsg(_("E260: Missing name after ->"));
4833 return FAIL;
4834 }
4835
4836 // Check for the "(". Skip over white space after it.
4837 if (name[len] != '(')
4838 {
4839 if (verbose)
4840 semsg(_(e_missingparen), name);
4841 return FAIL;
4842 }
4843 *arg += len;
4844
4845 vim_memset(&funcexe, 0, sizeof(funcexe));
4846 funcexe.evaluate = evaluate;
4847 funcexe.basetv = &base;
4848 rettv->v_type = VAR_UNKNOWN;
4849 ret = get_func_tv(name, len, rettv, arg, &funcexe);
4850
4851 /* Clear the funcref afterwards, so that deleting it while
4852 * evaluating the arguments is possible (see test55). */
4853 if (evaluate)
4854 clear_tv(&base);
4855
4856 /* Stop the expression evaluation when immediately aborting on
4857 * error, or when an interrupt occurred or an exception was thrown
4858 * but not caught. */
4859 if (aborting())
4860 {
4861 if (ret == OK)
4862 clear_tv(rettv);
4863 ret = FAIL;
4864 }
4801 return ret; 4865 return ret;
4802 } 4866 }
4803 4867
4804 /* 4868 /*
4805 * Evaluate an "[expr]" or "[expr:expr]" index. Also "dict.key". 4869 * Evaluate an "[expr]" or "[expr:expr]" index. Also "dict.key".
7357 7421
7358 name[len] = cc; 7422 name[len] = cc;
7359 } 7423 }
7360 7424
7361 /* 7425 /*
7362 * Handle expr[expr], expr[expr:expr] subscript and .name lookup. 7426 * Handle:
7363 * Also handle function call with Funcref variable: func(expr) 7427 * - expr[expr], expr[expr:expr] subscript
7364 * Can all be combined: dict.func(expr)[idx]['func'](expr) 7428 * - ".name" lookup
7429 * - function call with Funcref variable: func(expr)
7430 * - method call: var->method()
7431 *
7432 * Can all be combined in any order: dict.func(expr)[idx]['func'](expr)->len()
7365 */ 7433 */
7366 int 7434 int
7367 handle_subscript( 7435 handle_subscript(
7368 char_u **arg, 7436 char_u **arg,
7369 typval_T *rettv, 7437 typval_T *rettv,
7376 typval_T functv; 7444 typval_T functv;
7377 7445
7378 // "." is ".name" lookup when we found a dict or when evaluating and 7446 // "." is ".name" lookup when we found a dict or when evaluating and
7379 // scriptversion is at least 2, where string concatenation is "..". 7447 // scriptversion is at least 2, where string concatenation is "..".
7380 while (ret == OK 7448 while (ret == OK
7381 && (**arg == '[' 7449 && (((**arg == '['
7382 || (**arg == '.' && (rettv->v_type == VAR_DICT 7450 || (**arg == '.' && (rettv->v_type == VAR_DICT
7383 || (!evaluate 7451 || (!evaluate
7384 && (*arg)[1] != '.' 7452 && (*arg)[1] != '.'
7385 && current_sctx.sc_version >= 2))) 7453 && current_sctx.sc_version >= 2)))
7386 || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC 7454 || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
7387 || rettv->v_type == VAR_PARTIAL))) 7455 || rettv->v_type == VAR_PARTIAL)))
7388 && !VIM_ISWHITE(*(*arg - 1))) 7456 && !VIM_ISWHITE(*(*arg - 1)))
7457 || (**arg == '-' && (*arg)[1] == '>')))
7389 { 7458 {
7390 if (**arg == '(') 7459 if (**arg == '(')
7391 { 7460 {
7392 partial_T *pt = NULL; 7461 partial_T *pt = NULL;
7393 funcexe_T funcexe; 7462 funcexe_T funcexe;
7408 s = functv.vval.v_string; 7477 s = functv.vval.v_string;
7409 } 7478 }
7410 else 7479 else
7411 s = (char_u *)""; 7480 s = (char_u *)"";
7412 7481
7413 funcexe.argv_func = NULL; 7482 vim_memset(&funcexe, 0, sizeof(funcexe));
7414 funcexe.firstline = curwin->w_cursor.lnum; 7483 funcexe.firstline = curwin->w_cursor.lnum;
7415 funcexe.lastline = curwin->w_cursor.lnum; 7484 funcexe.lastline = curwin->w_cursor.lnum;
7416 funcexe.doesrange = NULL;
7417 funcexe.evaluate = evaluate; 7485 funcexe.evaluate = evaluate;
7418 funcexe.partial = pt; 7486 funcexe.partial = pt;
7419 funcexe.selfdict = selfdict; 7487 funcexe.selfdict = selfdict;
7420 ret = get_func_tv(s, -1, rettv, arg, &funcexe); 7488 ret = get_func_tv(s, -1, rettv, arg, &funcexe);
7421 7489
7433 clear_tv(rettv); 7501 clear_tv(rettv);
7434 ret = FAIL; 7502 ret = FAIL;
7435 } 7503 }
7436 dict_unref(selfdict); 7504 dict_unref(selfdict);
7437 selfdict = NULL; 7505 selfdict = NULL;
7506 }
7507 else if (**arg == '-')
7508 {
7509 if (eval_method(arg, rettv, evaluate, verbose) == FAIL)
7510 {
7511 clear_tv(rettv);
7512 ret = FAIL;
7513 }
7438 } 7514 }
7439 else /* **arg == '[' || **arg == '.' */ 7515 else /* **arg == '[' || **arg == '.' */
7440 { 7516 {
7441 dict_unref(selfdict); 7517 dict_unref(selfdict);
7442 if (rettv->v_type == VAR_DICT) 7518 if (rettv->v_type == VAR_DICT)