patch 9.1.1577: Vim9: no generic support yet

Problem:  Vim9: no generic support yet
Solution: Add support for generic functions, funcrefs and object/class
          methods (Yegappan Lakshmanan).

closes: #17313

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yegappan Lakshmanan
2025-07-21 21:36:08 +02:00
committed by Christian Brabandt
parent b486ed8266
commit 3416cee36f
35 changed files with 5905 additions and 161 deletions

View File

@ -1620,12 +1620,12 @@ get_lval_tuple(
* The method index, method function pointer and method type are returned in
* "lp".
*/
static void
static int
get_lval_oc_method(
lval_T *lp,
class_T *cl,
char_u *key,
char_u *key_end,
char_u **key_end,
vartype_T v_type)
{
// Look for a method with this name.
@ -1637,8 +1637,13 @@ get_lval_oc_method(
ufunc_T *fp;
fp = method_lookup(cl, round == 1 ? VAR_CLASS : VAR_OBJECT,
key, key_end - key, &m_idx);
key, *key_end - key, &m_idx);
lp->ll_oi = m_idx;
// process generic method (if present)
if (fp && (fp = eval_generic_func(fp, key, key_end)) == NULL)
return FAIL;
if (fp != NULL)
{
lp->ll_ufunc = fp;
@ -1646,6 +1651,8 @@ get_lval_oc_method(
break;
}
}
return OK;
}
/*
@ -1711,7 +1718,7 @@ get_lval_oc_variable(
get_lval_class_or_obj(
lval_T *lp,
char_u *key,
char_u *key_end,
char_u **key_end,
vartype_T v_type,
class_T *cl_exec,
int flags,
@ -1747,19 +1754,20 @@ get_lval_class_or_obj(
lp->ll_valtype = NULL;
if (flags & GLV_PREFER_FUNC)
get_lval_oc_method(lp, cl, key, key_end, v_type);
if (get_lval_oc_method(lp, cl, key, key_end, v_type) == FAIL)
return FAIL;
// Look for object/class member variable
if (lp->ll_valtype == NULL)
{
if (get_lval_oc_variable(lp, cl, key, key_end, v_type, cl_exec, flags)
if (get_lval_oc_variable(lp, cl, key, *key_end, v_type, cl_exec, flags)
== FAIL)
return FAIL;
}
if (lp->ll_valtype == NULL)
{
member_not_found_msg(cl, v_type, key, key_end - key);
member_not_found_msg(cl, v_type, key, *key_end - key);
return FAIL;
}
@ -2039,7 +2047,7 @@ get_lval_subscript(
}
else // v_type == VAR_CLASS || v_type == VAR_OBJECT
{
if (get_lval_class_or_obj(lp, key, p, v_type, cl_exec, flags,
if (get_lval_class_or_obj(lp, key, &p, v_type, cl_exec, flags,
quiet) == FAIL)
goto done;
}
@ -2213,7 +2221,7 @@ get_lval(
// parse the type after the name
lp->ll_type = parse_type(&tp,
&SCRIPT_ITEM(current_sctx.sc_sid)->sn_type_list,
!quiet);
NULL, NULL, !quiet);
if (lp->ll_type == NULL && !quiet)
return NULL;
lp->ll_name_end = tp;
@ -3179,6 +3187,8 @@ eval_func(
funcexe.fe_basetv = basetv;
funcexe.fe_check_type = type;
funcexe.fe_found_var = found_var;
if (evalarg != NULL)
funcexe.fe_cctx = evalarg->eval_cctx;
ret = get_func_tv(s, len, rettv, arg, evalarg, &funcexe);
}
vim_free(s);
@ -4725,7 +4735,7 @@ eval8(
{
++*arg;
ga_init2(&type_list, sizeof(type_T *), 10);
want_type = parse_type(arg, &type_list, TRUE);
want_type = parse_type(arg, &type_list, NULL, NULL, TRUE);
if (want_type == NULL && (evaluate || **arg != '>'))
{
clear_type_list(&type_list);
@ -4973,7 +4983,7 @@ eval9_nested_expr(
if (vim9script)
{
ret = get_lambda_tv(arg, rettv, TRUE, evalarg);
ret = get_lambda_tv(arg, rettv, TRUE, evalarg, NULL);
if (ret == OK && evaluate)
{
ufunc_T *ufunc = rettv->vval.v_partial->pt_func;
@ -5062,7 +5072,8 @@ eval9_var_func_name(
semsg(_(e_cannot_use_s_colon_in_vim9_script_str), s);
ret = FAIL;
}
else if ((vim9script ? **arg : *skipwhite(*arg)) == '(')
else if ((vim9script ? **arg : *skipwhite(*arg)) == '('
|| (vim9script && generic_func_call(arg)))
{
// "name(..." recursive!
*arg = skipwhite(*arg);
@ -5079,6 +5090,12 @@ eval9_var_func_name(
*name_start = s;
ret = eval_variable(s, len, 0, rettv, NULL,
EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT);
// skip the generic function arguments (if present)
// they are already processed by eval_variable
if (ret == OK && vim9script && **arg == '<'
&& rettv->v_type == VAR_FUNC)
ret = skip_generic_func_type_args(arg);
}
}
else
@ -5230,7 +5247,7 @@ eval9(
case '{': if (vim9script)
ret = NOTDONE;
else
ret = get_lambda_tv(arg, rettv, vim9script, evalarg);
ret = get_lambda_tv(arg, rettv, vim9script, evalarg, NULL);
if (ret == NOTDONE)
ret = eval_dict(arg, rettv, evalarg, FALSE);
break;
@ -5438,6 +5455,8 @@ call_func_rettv(
funcexe.fe_partial = pt;
funcexe.fe_selfdict = selfdict;
funcexe.fe_basetv = basetv;
if (evalarg != NULL)
funcexe.fe_cctx = evalarg->eval_cctx;
ret = get_func_tv(s, -1, rettv, arg, evalarg, &funcexe);
theend:
@ -5471,7 +5490,7 @@ eval_lambda(
if (**arg == '{')
{
// ->{lambda}()
ret = get_lambda_tv(arg, rettv, FALSE, evalarg);
ret = get_lambda_tv(arg, rettv, FALSE, evalarg, NULL);
}
else
{
@ -5663,6 +5682,15 @@ eval_index(
;
if (keylen == 0)
return FAIL;
if (vim9script && key[keylen] == '<')
{
// skip generic type arguments
char_u *p = &key[keylen];
if (skip_generic_func_type_args(&p) == FAIL)
return FAIL;
keylen = p - key;
}
*arg = key + keylen;
}
else
@ -7374,7 +7402,19 @@ handle_subscript(
else
{
rettv->v_type = VAR_FUNC;
rettv->vval.v_string = vim_strnsave(ufunc->uf_name, ufunc->uf_namelen);
if (**arg == '<')
{
char_u *s = get_generic_func_name(ufunc, arg);
if (s != NULL)
rettv->vval.v_string = s;
else
ret = FAIL;
}
else
{
rettv->vval.v_string =
vim_strnsave(ufunc->uf_name, ufunc->uf_namelen);
}
}
continue;
}