summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-12-14 20:59:32 +0000
committerBram Moolenaar <Bram@vim.org>2022-12-14 20:59:32 +0000
commit3d473ee1a6aed7cb9eae458bbd8d42dffdc754f9 (patch)
tree787ae08f91baa1ef09a13c88adf209b7486e892b
parentf94178db8d7324099b1bf916a0dff022c08abdff (diff)
patch 9.0.1060: private and public object members are not implemented yetv9.0.1060
problem: Private and public object members are not implemented yet. Solution: Implement private and public object members.
-rw-r--r--src/errors.h10
-rw-r--r--src/eval.c55
-rw-r--r--src/structs.h10
-rw-r--r--src/testdir/test_vim9_class.vim27
-rw-r--r--src/version.c2
-rw-r--r--src/vim9class.c45
-rw-r--r--src/vim9expr.c7
7 files changed, 144 insertions, 12 deletions
diff --git a/src/errors.h b/src/errors.h
index 2cf29cc7f7..6299ccd564 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3378,4 +3378,14 @@ EXTERN char e_cannot_get_object_member_type_from_initializer_str[]
INIT(= N_("E1329: Cannot get object member type from initializer: %s"));
EXTERN char e_invalid_type_for_object_member_str[]
INIT(= N_("E1330: Invalid type for object member: %s"));
+EXTERN char e_public_must_be_followed_by_this[]
+ INIT(= N_("E1331: Public must be followed by \"this\""));
+EXTERN char e_public_object_member_name_cannot_start_with_underscore_str[]
+ INIT(= N_("E1332: Public object member name cannot start with underscore: %s"));
+EXTERN char e_cannot_access_private_object_member_str[]
+ INIT(= N_("E1333: Cannot access private object member: %s"));
+EXTERN char e_object_member_not_found_str[]
+ INIT(= N_("E1334: Object member not found: %s"));
+EXTERN char e_object_member_is_not_writable_str[]
+ INIT(= N_("E1335: Object member is not writable: %s"));
#endif
diff --git a/src/eval.c b/src/eval.c
index 286e5af273..5baaa99062 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1194,6 +1194,7 @@ get_lval(
while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
{
if (*p == '.' && lp->ll_tv->v_type != VAR_DICT
+ && lp->ll_tv->v_type != VAR_OBJECT
&& lp->ll_tv->v_type != VAR_CLASS)
{
if (!quiet)
@@ -1203,6 +1204,7 @@ get_lval(
if (lp->ll_tv->v_type != VAR_LIST
&& lp->ll_tv->v_type != VAR_DICT
&& lp->ll_tv->v_type != VAR_BLOB
+ && lp->ll_tv->v_type != VAR_OBJECT
&& lp->ll_tv->v_type != VAR_CLASS)
{
if (!quiet)
@@ -1509,10 +1511,55 @@ get_lval(
lp->ll_tv = &lp->ll_li->li_tv;
}
- else // v_type == VAR_CLASS
+ else // v_type == VAR_CLASS || v_type == VAR_OBJECT
{
- // TODO: check object members and methods if
- // "key" points name start, "p" to the end
+ class_T *cl = (lp->ll_tv->v_type == VAR_OBJECT
+ && lp->ll_tv->vval.v_object != NULL)
+ ? lp->ll_tv->vval.v_object->obj_class
+ : lp->ll_tv->vval.v_class;
+ // TODO: what if class is NULL?
+ if (cl != NULL)
+ {
+ lp->ll_valtype = NULL;
+ for (int i = 0; i < cl->class_obj_member_count; ++i)
+ {
+ objmember_T *om = cl->class_obj_members + i;
+ if (STRNCMP(om->om_name, key, p - key) == 0
+ && om->om_name[p - key] == NUL)
+ {
+ switch (om->om_access)
+ {
+ case ACCESS_PRIVATE:
+ semsg(_(e_cannot_access_private_object_member_str),
+ om->om_name);
+ return NULL;
+ case ACCESS_READ:
+ if (!(flags & GLV_READ_ONLY))
+ {
+ semsg(_(e_object_member_is_not_writable_str),
+ om->om_name);
+ return NULL;
+ }
+ break;
+ case ACCESS_ALL:
+ break;
+ }
+
+ lp->ll_valtype = om->om_type;
+
+ if (lp->ll_tv->v_type == VAR_OBJECT)
+ lp->ll_tv = ((typval_T *)(
+ lp->ll_tv->vval.v_object + 1)) + i;
+ // TODO: what about a class?
+ break;
+ }
+ }
+ if (lp->ll_valtype == NULL)
+ {
+ semsg(_(e_object_member_not_found_str), key);
+ return NULL;
+ }
+ }
}
}
@@ -1640,7 +1687,7 @@ set_var_lval(
else
{
/*
- * Assign to a List or Dictionary item.
+ * Assign to a List, Dictionary or Object item.
*/
if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
&& (flags & ASSIGN_FOR_LOOP) == 0)
diff --git a/src/structs.h b/src/structs.h
index 46f9b0c3d1..2f9a78268a 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1459,11 +1459,18 @@ typedef struct {
type_T *type_decl; // declared type or equal to type_current
} type2_T;
+typedef enum {
+ ACCESS_PRIVATE, // read/write only inside th class
+ ACCESS_READ, // read everywhere, write only inside th class
+ ACCESS_ALL // read/write everywhere
+} omacc_T;
+
/*
* Entry for an object member variable.
*/
typedef struct {
char_u *om_name; // allocated
+ omacc_T om_access;
type_T *om_type;
char_u *om_init; // allocated
} objmember_T;
@@ -1720,7 +1727,8 @@ struct ufunc_S
def_status_T uf_def_status; // UF_NOT_COMPILED, UF_TO_BE_COMPILED, etc.
int uf_dfunc_idx; // only valid if uf_def_status is UF_COMPILED
- class_T *uf_class; // for object method and constructor
+ class_T *uf_class; // for object method and constructor; does not
+ // count for class_refcount
garray_T uf_args; // arguments, including optional arguments
garray_T uf_def_args; // default argument expressions
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index 79459d1570..d30c7b468b 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -283,6 +283,33 @@ def Test_class_object_member_inits()
v9.CheckScriptFailure(lines, 'E1330:')
enddef
+def Test_class_object_member_access()
+ var lines =<< trim END
+ vim9script
+ class Triple
+ this._one = 1
+ this.two = 2
+ public this.three = 3
+
+ def GetOne(): number
+ return this._one
+ enddef
+ endclass
+
+ var trip = Triple.new()
+ assert_equal(1, trip.GetOne())
+ assert_equal(2, trip.two)
+ assert_equal(3, trip.three)
+ assert_fails('echo trip._one', 'E1333')
+
+ assert_fails('trip._one = 11', 'E1333')
+ assert_fails('trip.two = 22', 'E1335')
+ trip.three = 33
+ assert_equal(33, trip.three)
+ END
+ v9.CheckScriptSuccess(lines)
+enddef
+
def Test_class_object_to_string()
var lines =<< trim END
vim9script
diff --git a/src/version.c b/src/version.c
index 5d9ea5deb5..6951668e54 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1060,
+/**/
1059,
/**/
1058,
diff --git a/src/vim9class.c b/src/vim9class.c
index 86327b499e..da44c3ddf4 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -110,19 +110,40 @@ ex_class(exarg_T *eap)
break;
}
- // "this.varname"
// "this._varname"
- // TODO:
- // "public this.varname"
- if (STRNCMP(line, "this", 4) == 0)
+ // "this.varname"
+ // "public this.varname"
+ int has_public = FALSE;
+ if (checkforcmd(&p, "public", 3))
+ {
+ if (STRNCMP(line, "public", 6) != 0)
+ {
+ semsg(_(e_command_cannot_be_shortened_str), line);
+ break;
+ }
+ has_public = TRUE;
+ p = skipwhite(line + 6);
+
+ if (STRNCMP(p, "this", 4) != 0)
+ {
+ emsg(_(e_public_must_be_followed_by_this));
+ break;
+ }
+ }
+ if (STRNCMP(p, "this", 4) == 0)
{
- if (line[4] != '.' || !eval_isnamec1(line[5]))
+ if (p[4] != '.' || !eval_isnamec1(p[5]))
{
- semsg(_(e_invalid_object_member_declaration_str), line);
+ semsg(_(e_invalid_object_member_declaration_str), p);
break;
}
- char_u *varname = line + 5;
+ char_u *varname = p + 5;
char_u *varname_end = to_name_end(varname, FALSE);
+ if (*varname == '_' && has_public)
+ {
+ semsg(_(e_public_object_member_name_cannot_start_with_underscore_str), line);
+ break;
+ }
char_u *colon = skipwhite(varname_end);
char_u *type_arg = colon;
@@ -199,6 +220,9 @@ ex_class(exarg_T *eap)
objmember_T *m = ((objmember_T *)objmembers.ga_data)
+ objmembers.ga_len;
m->om_name = vim_strnsave(varname, varname_end - varname);
+ m->om_access = has_public ? ACCESS_ALL
+ : *varname == '_' ? ACCESS_PRIVATE
+ : ACCESS_READ;
m->om_type = type;
if (expr_end > expr_start)
m->om_init = vim_strnsave(expr_start, expr_end - expr_start);
@@ -551,6 +575,13 @@ class_object_index(
objmember_T *m = &cl->class_obj_members[i];
if (STRNCMP(name, m->om_name, len) == 0 && m->om_name[len] == NUL)
{
+ if (*name == '_')
+ {
+ semsg(_(e_cannot_access_private_object_member_str),
+ m->om_name);
+ return FAIL;
+ }
+
// The object only contains a pointer to the class, the member
// values array follows right after that.
object_T *obj = rettv->vval.v_object;
diff --git a/src/vim9expr.c b/src/vim9expr.c
index c8054e52d0..6c9385c838 100644
--- a/src/vim9expr.c
+++ b/src/vim9expr.c
@@ -281,6 +281,13 @@ compile_class_object_index(cctx_T *cctx, char_u **arg, type_T *type)
objmember_T *m = &cl->class_obj_members[i];
if (STRNCMP(name, m->om_name, len) == 0 && m->om_name[len] == NUL)
{
+ if (*name == '_' && cctx->ctx_ufunc->uf_class != cl)
+ {
+ semsg(_(e_cannot_access_private_object_member_str),
+ m->om_name);
+ return FAIL;
+ }
+
generate_GET_OBJ_MEMBER(cctx, i, m->om_type);
*arg = name_end;