]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1060: private and public object members are not implemented yet v9.0.1060
authorBram Moolenaar <Bram@vim.org>
Wed, 14 Dec 2022 20:59:32 +0000 (20:59 +0000)
committerBram Moolenaar <Bram@vim.org>
Wed, 14 Dec 2022 20:59:32 +0000 (20:59 +0000)
problem:    Private and public object members are not implemented yet.
Solution:   Implement private and public object members.

src/errors.h
src/eval.c
src/structs.h
src/testdir/test_vim9_class.vim
src/version.c
src/vim9class.c
src/vim9expr.c

index 2cf29cc7f7e4637b5229121be425089b05ca745c..6299ccd5643e6a3ecc28e4384f1cf96a0b125c35 100644 (file)
@@ -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
index 286e5af2730d11d0265280a13d98a012e0b496a4..5baaa99062ccea557ff4eb2291055bb5a778f7c9 100644 (file)
@@ -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)
index 46f9b0c3d1fa5b7c078d33fcf92404d5343b1cb5..2f9a78268a30a4ac2bfe6f50c091e045fbcec552 100644 (file)
@@ -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
index 79459d1570cd1a5b1f41f7ac7c2fe74f00c37489..d30c7b468b1bbf70fea98354d2a9c6ed947d458d 100644 (file)
@@ -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
index 5d9ea5deb598bfec2351a671c5d91dd466713f40..6951668e5465e43d06465fa398ca1116f5c209d1 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1060,
 /**/
     1059,
 /**/
index 86327b499e8b798eea33f48c01fabe35f93281b4..da44c3ddf451e2f920c753a442f165d64fa7adea 100644 (file)
@@ -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;
index c8054e52d0055c819d2fb30a6417919cba86a03e..6c9385c8381c58af27dfc268417cd082a888e227 100644 (file)
@@ -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;