patch 9.0.1031: Vim9 class is not implemented yet
Problem: Vim9 class is not implemented yet.
Solution: Add very basic class support.
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 17066b0..ab9e965 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -43,6 +43,20 @@
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 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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