0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

patch 9.0.1031: Vim9 class is not implemented yet

Problem:    Vim9 class is not implemented yet.
Solution:   Add very basic class support.
This commit is contained in:
Bram Moolenaar
2022-12-08 15:32:33 +00:00
parent 038e6d20e6
commit 00b28d6c23
29 changed files with 1066 additions and 74 deletions

View File

@@ -43,6 +43,20 @@ lookup_local(char_u *name, size_t len, lvar_T *lvar, cctx_T *cctx)
if (len == 0)
return FAIL;
if (len == 4 && STRNCMP(name, "this", 4) == 0
&& cctx->ctx_ufunc != NULL
&& (cctx->ctx_ufunc->uf_flags & FC_OBJECT))
{
if (lvar != NULL)
{
CLEAR_POINTER(lvar);
lvar->lv_name = (char_u *)"this";
if (cctx->ctx_ufunc->uf_class != NULL)
lvar->lv_type = &cctx->ctx_ufunc->uf_class->class_type;
}
return OK;
}
// Find local in current function scope.
for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx)
{
@@ -296,7 +310,11 @@ variable_exists(char_u *name, size_t len, cctx_T *cctx)
{
return (cctx != NULL
&& (lookup_local(name, len, NULL, cctx) == OK
|| arg_exists(name, len, NULL, NULL, NULL, cctx) == OK))
|| arg_exists(name, len, NULL, NULL, NULL, cctx) == OK
|| (len == 4
&& cctx->ctx_ufunc != NULL
&& (cctx->ctx_ufunc->uf_flags & FC_OBJECT)
&& STRNCMP(name, "this", 4) == 0)))
|| script_var_exists(name, len, cctx, NULL) == OK
|| find_imported(name, len, FALSE) != NULL;
}
@@ -957,7 +975,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx, garray_T *lines_to_free)
goto theend;
}
ufunc = define_function(eap, lambda_name, lines_to_free);
ufunc = define_function(eap, lambda_name, lines_to_free, NULL);
if (ufunc == NULL)
{
r = eap->skip ? OK : FAIL;
@@ -1450,6 +1468,7 @@ compile_lhs(
lhs->lhs_dest = dest_local;
lhs->lhs_vimvaridx = -1;
lhs->lhs_scriptvar_idx = -1;
lhs->lhs_member_idx = -1;
// "dest_end" is the end of the destination, including "[expr]" or
// ".name".
@@ -1509,7 +1528,7 @@ compile_lhs(
else
{
// No specific kind of variable recognized, just a name.
if (check_reserved_name(lhs->lhs_name) == FAIL)
if (check_reserved_name(lhs->lhs_name, cctx) == FAIL)
return FAIL;
if (lookup_local(var_start, lhs->lhs_varlen,
@@ -1757,8 +1776,16 @@ compile_lhs(
lhs->lhs_type = &t_any;
}
if (lhs->lhs_type->tt_member == NULL)
if (lhs->lhs_type == NULL || lhs->lhs_type->tt_member == NULL)
lhs->lhs_member_type = &t_any;
else if (lhs->lhs_type->tt_type == VAR_CLASS
|| lhs->lhs_type->tt_type == VAR_OBJECT)
{
// for an object or class member get the type of the member
class_T *cl = (class_T *)lhs->lhs_type->tt_member;
lhs->lhs_member_type = class_member_type(cl, after + 1,
lhs->lhs_end, &lhs->lhs_member_idx);
}
else
lhs->lhs_member_type = lhs->lhs_type->tt_member;
}
@@ -1880,6 +1907,11 @@ compile_assign_index(
r = FAIL;
}
}
else if (lhs->lhs_member_idx >= 0)
{
// object member index
r = generate_PUSHNR(cctx, lhs->lhs_member_idx);
}
else // if (*p == '.')
{
char_u *key_end = to_name_end(p + 1, TRUE);
@@ -1996,7 +2028,7 @@ compile_assign_unlet(
return FAIL;
}
if (lhs->lhs_type == &t_any)
if (lhs->lhs_type == NULL || lhs->lhs_type == &t_any)
{
// Index on variable of unknown type: check at runtime.
dest_type = VAR_ANY;
@@ -2042,8 +2074,12 @@ compile_assign_unlet(
if (compile_load_lhs(lhs, var_start, rhs_type, cctx) == FAIL)
return FAIL;
if (dest_type == VAR_LIST || dest_type == VAR_DICT
|| dest_type == VAR_BLOB || dest_type == VAR_ANY)
if (dest_type == VAR_LIST
|| dest_type == VAR_DICT
|| dest_type == VAR_BLOB
|| dest_type == VAR_CLASS
|| dest_type == VAR_OBJECT
|| dest_type == VAR_ANY)
{
if (is_assign)
{
@@ -2466,6 +2502,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
case VAR_PARTIAL:
case VAR_VOID:
case VAR_INSTR:
case VAR_CLASS:
case VAR_OBJECT:
case VAR_SPECIAL: // cannot happen
// This is skipped for local variables, they are always
// initialized to zero. But in a "for" or "while" loop
@@ -2897,6 +2935,22 @@ compile_def_function(
if (check_args_shadowing(ufunc, &cctx) == FAIL)
goto erret;
// For an object method and constructor "this" is the first local variable.
if (ufunc->uf_flags & FC_OBJECT)
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
if (GA_GROW_FAILS(&dfunc->df_var_names, 1))
goto erret;
((char_u **)dfunc->df_var_names.ga_data)[0] =
vim_strsave((char_u *)"this");
++dfunc->df_var_names.ga_len;
// In the constructor allocate memory for the object.
if ((ufunc->uf_flags & FC_NEW) == FC_NEW)
generate_CONSTRUCT(&cctx, ufunc->uf_class);
}
if (ufunc->uf_def_args.ga_len > 0)
{
int count = ufunc->uf_def_args.ga_len;
@@ -3500,14 +3554,19 @@ nextline:
{
if (ufunc->uf_ret_type->tt_type == VAR_UNKNOWN)
ufunc->uf_ret_type = &t_void;
else if (ufunc->uf_ret_type->tt_type != VAR_VOID)
else if (ufunc->uf_ret_type->tt_type != VAR_VOID
&& (ufunc->uf_flags & FC_NEW) != FC_NEW)
{
emsg(_(e_missing_return_statement));
goto erret;
}
// Return void if there is no return at the end.
generate_instr(&cctx, ISN_RETURN_VOID);
// For a constructor return the object.
if ((ufunc->uf_flags & FC_NEW) == FC_NEW)
generate_instr(&cctx, ISN_RETURN_OBJECT);
else
generate_instr(&cctx, ISN_RETURN_VOID);
}
// When compiled with ":silent!" and there was an error don't consider the