mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 9.0.1060: private and public object members are not implemented yet
problem: Private and public object members are not implemented yet. Solution: Implement private and public object members.
This commit is contained in:
10
src/errors.h
10
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"));
|
INIT(= N_("E1329: Cannot get object member type from initializer: %s"));
|
||||||
EXTERN char e_invalid_type_for_object_member_str[]
|
EXTERN char e_invalid_type_for_object_member_str[]
|
||||||
INIT(= N_("E1330: Invalid type for object member: %s"));
|
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
|
#endif
|
||||||
|
55
src/eval.c
55
src/eval.c
@@ -1194,6 +1194,7 @@ get_lval(
|
|||||||
while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
|
while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
|
||||||
{
|
{
|
||||||
if (*p == '.' && lp->ll_tv->v_type != VAR_DICT
|
if (*p == '.' && lp->ll_tv->v_type != VAR_DICT
|
||||||
|
&& lp->ll_tv->v_type != VAR_OBJECT
|
||||||
&& lp->ll_tv->v_type != VAR_CLASS)
|
&& lp->ll_tv->v_type != VAR_CLASS)
|
||||||
{
|
{
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
@@ -1203,6 +1204,7 @@ get_lval(
|
|||||||
if (lp->ll_tv->v_type != VAR_LIST
|
if (lp->ll_tv->v_type != VAR_LIST
|
||||||
&& lp->ll_tv->v_type != VAR_DICT
|
&& lp->ll_tv->v_type != VAR_DICT
|
||||||
&& lp->ll_tv->v_type != VAR_BLOB
|
&& lp->ll_tv->v_type != VAR_BLOB
|
||||||
|
&& lp->ll_tv->v_type != VAR_OBJECT
|
||||||
&& lp->ll_tv->v_type != VAR_CLASS)
|
&& lp->ll_tv->v_type != VAR_CLASS)
|
||||||
{
|
{
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
@@ -1509,10 +1511,55 @@ get_lval(
|
|||||||
|
|
||||||
lp->ll_tv = &lp->ll_li->li_tv;
|
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
|
class_T *cl = (lp->ll_tv->v_type == VAR_OBJECT
|
||||||
// "key" points name start, "p" to the end
|
&& 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
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Assign to a List or Dictionary item.
|
* Assign to a List, Dictionary or Object item.
|
||||||
*/
|
*/
|
||||||
if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
|
if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
|
||||||
&& (flags & ASSIGN_FOR_LOOP) == 0)
|
&& (flags & ASSIGN_FOR_LOOP) == 0)
|
||||||
|
@@ -1459,11 +1459,18 @@ typedef struct {
|
|||||||
type_T *type_decl; // declared type or equal to type_current
|
type_T *type_decl; // declared type or equal to type_current
|
||||||
} type2_T;
|
} 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.
|
* Entry for an object member variable.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char_u *om_name; // allocated
|
char_u *om_name; // allocated
|
||||||
|
omacc_T om_access;
|
||||||
type_T *om_type;
|
type_T *om_type;
|
||||||
char_u *om_init; // allocated
|
char_u *om_init; // allocated
|
||||||
} objmember_T;
|
} objmember_T;
|
||||||
@@ -1720,7 +1727,8 @@ struct ufunc_S
|
|||||||
def_status_T uf_def_status; // UF_NOT_COMPILED, UF_TO_BE_COMPILED, etc.
|
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
|
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_args; // arguments, including optional arguments
|
||||||
garray_T uf_def_args; // default argument expressions
|
garray_T uf_def_args; // default argument expressions
|
||||||
|
@@ -283,6 +283,33 @@ def Test_class_object_member_inits()
|
|||||||
v9.CheckScriptFailure(lines, 'E1330:')
|
v9.CheckScriptFailure(lines, 'E1330:')
|
||||||
enddef
|
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()
|
def Test_class_object_to_string()
|
||||||
var lines =<< trim END
|
var lines =<< trim END
|
||||||
vim9script
|
vim9script
|
||||||
|
@@ -695,6 +695,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1060,
|
||||||
/**/
|
/**/
|
||||||
1059,
|
1059,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -110,19 +110,40 @@ ex_class(exarg_T *eap)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "this.varname"
|
|
||||||
// "this._varname"
|
// "this._varname"
|
||||||
// TODO:
|
// "this.varname"
|
||||||
// "public this.varname"
|
// "public this.varname"
|
||||||
if (STRNCMP(line, "this", 4) == 0)
|
int has_public = FALSE;
|
||||||
|
if (checkforcmd(&p, "public", 3))
|
||||||
{
|
{
|
||||||
if (line[4] != '.' || !eval_isnamec1(line[5]))
|
if (STRNCMP(line, "public", 6) != 0)
|
||||||
{
|
{
|
||||||
semsg(_(e_invalid_object_member_declaration_str), line);
|
semsg(_(e_command_cannot_be_shortened_str), line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
char_u *varname = line + 5;
|
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 (p[4] != '.' || !eval_isnamec1(p[5]))
|
||||||
|
{
|
||||||
|
semsg(_(e_invalid_object_member_declaration_str), p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
char_u *varname = p + 5;
|
||||||
char_u *varname_end = to_name_end(varname, FALSE);
|
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 *colon = skipwhite(varname_end);
|
||||||
char_u *type_arg = colon;
|
char_u *type_arg = colon;
|
||||||
@@ -199,6 +220,9 @@ ex_class(exarg_T *eap)
|
|||||||
objmember_T *m = ((objmember_T *)objmembers.ga_data)
|
objmember_T *m = ((objmember_T *)objmembers.ga_data)
|
||||||
+ objmembers.ga_len;
|
+ objmembers.ga_len;
|
||||||
m->om_name = vim_strnsave(varname, varname_end - varname);
|
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;
|
m->om_type = type;
|
||||||
if (expr_end > expr_start)
|
if (expr_end > expr_start)
|
||||||
m->om_init = vim_strnsave(expr_start, 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];
|
objmember_T *m = &cl->class_obj_members[i];
|
||||||
if (STRNCMP(name, m->om_name, len) == 0 && m->om_name[len] == NUL)
|
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
|
// The object only contains a pointer to the class, the member
|
||||||
// values array follows right after that.
|
// values array follows right after that.
|
||||||
object_T *obj = rettv->vval.v_object;
|
object_T *obj = rettv->vval.v_object;
|
||||||
|
@@ -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];
|
objmember_T *m = &cl->class_obj_members[i];
|
||||||
if (STRNCMP(name, m->om_name, len) == 0 && m->om_name[len] == NUL)
|
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);
|
generate_GET_OBJ_MEMBER(cctx, i, m->om_type);
|
||||||
|
|
||||||
*arg = name_end;
|
*arg = name_end;
|
||||||
|
Reference in New Issue
Block a user