introduced a new class modifier #immutable to indicate that an instantiated object cannot be modified using basicAt:put:

This commit is contained in:
hyunghwan.chung 2017-05-07 05:18:21 +00:00
parent 1dff630fdd
commit 63519c1ca3
8 changed files with 83 additions and 100 deletions

View File

@ -116,7 +116,7 @@ class(#character) String(Array)
## -------------------------------------------------------------------------------
class(#character,#final,#limited) Symbol(String)
class(#character,#final,#limited,#immutable) Symbol(String)
{
method asString
{

View File

@ -291,7 +291,7 @@ class Number(Magnitude)
}
}
class Integer(Number)
class(#limited) Integer(Number)
{
method timesRepeat: aBlock
{
@ -310,17 +310,17 @@ class SmallInteger(Integer)
method(#primitive) asError.
}
class(#liword) LargeInteger(Integer)
class(#liword,#limited) LargeInteger(Integer)
{
}
class(#liword) LargePositiveInteger(LargeInteger)
class(#liword,#immutable) LargePositiveInteger(LargeInteger)
{
method abs { ^self }
method sign { ^1 }
}
class(#liword) LargeNegativeInteger(LargeInteger)
class(#liword,#immutable) LargeNegativeInteger(LargeInteger)
{
method abs { ^self negated }
method sign { ^-1 }

View File

@ -50,9 +50,10 @@
enum class_mod_t
{
CLASS_FINAL = (1 << 0),
CLASS_LIMITED = (1 << 1),
CLASS_INDEXED = (1 << 2)
CLASS_FINAL = (1 << 0),
CLASS_LIMITED = (1 << 1),
CLASS_INDEXED = (1 << 2),
CLASS_IMMUTABLE = (1 << 3)
};
enum var_type_t
@ -107,6 +108,7 @@ static struct voca_t
{ 4, { 'f','r','o','m' } },
{ 9, { '#','h','a','l','f','w','o','r','d' } },
{ 2, { 'i','f' } },
{ 10, { '#','i','m','m','u','t','a','b','l','e' } },
{ 6, { 'i','m','p','o','r','t' } },
{ 8, { '#','i','n','c','l','u','d','e' } },
{ 8, { '#','l','i','b','e','r','a','l' } },
@ -165,6 +167,7 @@ enum voca_id_t
VOCA_FROM,
VOCA_HALFWORD_S,
VOCA_IF,
VOCA_IMMUTABLE_S,
VOCA_IMPORT,
VOCA_INCLUDE_S,
VOCA_LIBERAL_S,
@ -6407,9 +6410,10 @@ static int make_defined_class (moo_t* moo)
moo_oow_t spec, self_spec;
int just_made = 0, flags;
spec = MOO_CLASS_SPEC_MAKE (moo->c->cls.var[VAR_INSTANCE].total_count,
((moo->c->cls.flags & CLASS_INDEXED)? 1: 0),
moo->c->cls.indexed_type);
flags = 0;
if (moo->c->cls.flags & CLASS_INDEXED) flags |= MOO_CLASS_SPEC_FLAG_INDEXED;
if (moo->c->cls.flags & CLASS_IMMUTABLE) flags |= MOO_CLASS_SPEC_FLAG_IMMUTABLE;
spec = MOO_CLASS_SPEC_MAKE (moo->c->cls.var[VAR_INSTANCE].total_count, flags, moo->c->cls.indexed_type);
flags = 0;
if (moo->c->cls.flags & CLASS_FINAL) flags |= MOO_CLASS_SELFSPEC_FLAG_FINAL;
@ -6656,15 +6660,25 @@ static int __compile_class_definition (moo_t* moo, int extend)
moo->c->cls.flags |= CLASS_LIMITED;
GET_TOKEN(moo);
}
else if (is_token_symbol(moo, VOCA_IMMUTABLE_S))
{
if (moo->c->cls.flags & CLASS_IMMUTABLE)
{
set_syntax_error (moo, MOO_SYNERR_MODIFIERDUPL, TOKEN_LOC(moo), TOKEN_NAME(moo));
return -1;
}
moo->c->cls.flags |= CLASS_IMMUTABLE;
GET_TOKEN(moo);
}
else if (TOKEN_TYPE(moo) == MOO_IOTOK_COMMA || TOKEN_TYPE(moo) == MOO_IOTOK_EOF || TOKEN_TYPE(moo) == MOO_IOTOK_RPAREN)
{
/* no modifier is present */
/* no modifier is present */
set_syntax_error (moo, MOO_SYNERR_MODIFIER, TOKEN_LOC(moo), TOKEN_NAME(moo));
return -1;
}
else
{
/* invalid modifier */
/* invalid modifier */
set_syntax_error (moo, MOO_SYNERR_MODIFIERINVAL, TOKEN_LOC(moo), TOKEN_NAME(moo));
return -1;
}

View File

@ -1648,7 +1648,7 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
if (MOO_OBJ_GET_FLAGS_RDONLY(rcv))
{
/* TODO: better error handlign */
/* TODO: better error handling */
moo->errnum = MOO_EPERM;
return MOO_PF_FAILURE;
}
@ -1669,15 +1669,6 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
return MOO_PF_FAILURE;
}
if (MOO_OBJ_GET_CLASS(rcv) == moo->_symbol)
{
/* TODO: disallow change of some key kernel objects???? */
/* TODO: is it better to introduct a read-only mark in the object header instead of this class check??? */
/* read-only object */ /* TODO: DEVISE A WAY TO PASS a proper error from the primitive handler to MOO */
moo->errnum = MOO_EINVAL;
return MOO_PF_FAILURE;
}
switch (MOO_OBJ_GET_FLAGS_TYPE(rcv))
{
case MOO_OBJ_TYPE_BYTE:

View File

@ -174,14 +174,14 @@ static int ignite_1 (moo_t* moo)
moo->_apex = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_undefined_object = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_object = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_string = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_CHAR));
moo->_string = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, MOO_CLASS_SPEC_FLAG_INDEXED, MOO_OBJ_TYPE_CHAR));
moo->_symbol = alloc_kernel_class (moo,
MOO_CLASS_SELFSPEC_FLAG_FINAL | MOO_CLASS_SELFSPEC_FLAG_LIMITED,
0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_CHAR));
0, MOO_CLASS_SPEC_MAKE(0, MOO_CLASS_SPEC_FLAG_INDEXED | MOO_CLASS_SPEC_FLAG_IMMUTABLE, MOO_OBJ_TYPE_CHAR));
moo->_array = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_OOP));
moo->_byte_array = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_BYTE));
moo->_array = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, MOO_CLASS_SPEC_FLAG_INDEXED, MOO_OBJ_TYPE_OOP));
moo->_byte_array = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, MOO_CLASS_SPEC_FLAG_INDEXED, MOO_OBJ_TYPE_BYTE));
moo->_symbol_set = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_dictionary = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_system_dictionary = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
@ -189,15 +189,15 @@ static int ignite_1 (moo_t* moo)
moo->_namespace = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_pool_dictionary = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_method_dictionary = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_SET_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_method = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_METHOD_NAMED_INSTVARS, 1, MOO_OBJ_TYPE_OOP));
moo->_method = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_METHOD_NAMED_INSTVARS, MOO_CLASS_SPEC_FLAG_INDEXED, MOO_OBJ_TYPE_OOP));
moo->_association = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_ASSOCIATION_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_method_context = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_CONTEXT_NAMED_INSTVARS, 1, MOO_OBJ_TYPE_OOP));
moo->_block_context = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_CONTEXT_NAMED_INSTVARS, 1, MOO_OBJ_TYPE_OOP));
moo->_method_context = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_CONTEXT_NAMED_INSTVARS, MOO_CLASS_SPEC_FLAG_INDEXED, MOO_OBJ_TYPE_OOP));
moo->_block_context = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_CONTEXT_NAMED_INSTVARS, MOO_CLASS_SPEC_FLAG_INDEXED, MOO_OBJ_TYPE_OOP));
moo->_process = alloc_kernel_class (moo,
MOO_CLASS_SELFSPEC_FLAG_FINAL | MOO_CLASS_SELFSPEC_FLAG_LIMITED,
0, MOO_CLASS_SPEC_MAKE(MOO_PROCESS_NAMED_INSTVARS, 1, MOO_OBJ_TYPE_OOP));
0, MOO_CLASS_SPEC_MAKE(MOO_PROCESS_NAMED_INSTVARS, MOO_CLASS_SPEC_FLAG_INDEXED, MOO_OBJ_TYPE_OOP));
moo->_semaphore = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(MOO_SEMAPHORE_NAMED_INSTVARS, 0, MOO_OBJ_TYPE_OOP));
moo->_process_scheduler = alloc_kernel_class (moo,
@ -212,8 +212,8 @@ static int ignite_1 (moo_t* moo)
* Does this make sense? */
moo->_character = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_small_integer = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_large_positive_integer = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_LIWORD));
moo->_large_negative_integer = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_LIWORD));
moo->_large_positive_integer = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, MOO_CLASS_SPEC_FLAG_INDEXED | MOO_CLASS_SPEC_FLAG_IMMUTABLE, MOO_OBJ_TYPE_LIWORD));
moo->_large_negative_integer = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, MOO_CLASS_SPEC_FLAG_INDEXED | MOO_CLASS_SPEC_FLAG_IMMUTABLE, MOO_OBJ_TYPE_LIWORD));
moo->_small_pointer = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));
moo->_system = alloc_kernel_class (moo, 0, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP));

View File

@ -151,26 +151,32 @@
* The MOO_CLASS_SPEC_MAKE() macro creates a class spec value.
* _class->spec = MOO_SMOOI_TO_OOP(MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_CHAR));
*/
#define MOO_CLASS_SPEC_MAKE(named_instvar,is_indexed,indexed_type) ( \
(((moo_oow_t)(named_instvar)) << (MOO_OBJ_FLAGS_TYPE_BITS + 1)) | \
(((moo_oow_t)(indexed_type)) << 1) | (((moo_oow_t)is_indexed) & 1) )
#define MOO_CLASS_SPEC_MAKE(named_instvar,flags,indexed_type) ( \
(((moo_oow_t)(named_instvar)) << (MOO_OBJ_FLAGS_TYPE_BITS + 2)) | \
(((moo_oow_t)(indexed_type)) << 2) | (((moo_oow_t)flags) & 3) )
/* what is the number of named instance variables?
* MOO_CLASS_SPEC_NAMED_INSTVARS(MOO_OOP_TO_SMOOI(_class->spec))
*/
#define MOO_CLASS_SPEC_NAMED_INSTVARS(spec) \
(((moo_oow_t)(spec)) >> (MOO_OBJ_FLAGS_TYPE_BITS + 1))
(((moo_oow_t)(spec)) >> (MOO_OBJ_FLAGS_TYPE_BITS + 2))
/* is it a user-indexable class?
* all objects can be indexed with basicAt:.
* this indicates if an object can be instantiated with a dynamic size
* (new: size) and and can be indexed with at:.
*/
#define MOO_CLASS_SPEC_IS_INDEXED(spec) (((moo_oow_t)(spec)) & 1)
#define MOO_CLASS_SPEC_FLAGS(spec) (((moo_oow_t)(spec)) & 3)
/* if so, what is the indexing type? character? pointer? etc? */
#define MOO_CLASS_SPEC_INDEXED_TYPE(spec) \
((((moo_oow_t)(spec)) >> 1) & MOO_LBMASK(moo_oow_t, MOO_OBJ_FLAGS_TYPE_BITS))
((((moo_oow_t)(spec)) >> 2) & MOO_LBMASK(moo_oow_t, MOO_OBJ_FLAGS_TYPE_BITS))
#define MOO_CLASS_SPEC_FLAG_INDEXED (1 << 0)
#define MOO_CLASS_SPEC_FLAG_IMMUTABLE (1 << 1)
#define MOO_CLASS_SPEC_IS_INDEXED(spec) (MOO_CLASS_SPEC_FLAGS(spec) & MOO_CLASS_SPEC_FLAG_INDEXED)
#define MOO_CLASS_SPEC_IS_IMMUTABLE(spec) (MOO_CLASS_SPEC_FLAGS(spec) & MOO_CLASS_SPEC_FLAG_IMMUTABLE)
/* What is the maximum number of named instance variables?
* This limit is set so because the number must be encoded into the spec field
@ -180,7 +186,7 @@
* type of the spec field in the class object.
*/
#define MOO_MAX_NAMED_INSTVARS \
MOO_BITS_MAX(moo_oow_t, MOO_SMOOI_ABS_BITS - (MOO_OBJ_FLAGS_TYPE_BITS + 1))
MOO_BITS_MAX(moo_oow_t, MOO_SMOOI_ABS_BITS - (MOO_OBJ_FLAGS_TYPE_BITS + 2))
/* Given the number of named instance variables, what is the maximum number
* of indexed instance variables? The number of indexed instance variables

View File

@ -155,22 +155,22 @@ static MOO_INLINE moo_oop_t alloc_numeric_array (moo_t* moo, const void* ptr, mo
return hdr;
}
moo_oop_t moo_alloccharobj (moo_t* moo, const moo_ooch_t* ptr, moo_oow_t len)
MOO_INLINE moo_oop_t moo_alloccharobj (moo_t* moo, const moo_ooch_t* ptr, moo_oow_t len)
{
return alloc_numeric_array (moo, ptr, len, MOO_OBJ_TYPE_CHAR, MOO_SIZEOF(moo_ooch_t), 1);
}
moo_oop_t moo_allocbyteobj (moo_t* moo, const moo_oob_t* ptr, moo_oow_t len)
MOO_INLINE moo_oop_t moo_allocbyteobj (moo_t* moo, const moo_oob_t* ptr, moo_oow_t len)
{
return alloc_numeric_array (moo, ptr, len, MOO_OBJ_TYPE_BYTE, MOO_SIZEOF(moo_oob_t), 0);
}
moo_oop_t moo_allochalfwordobj (moo_t* moo, const moo_oohw_t* ptr, moo_oow_t len)
MOO_INLINE moo_oop_t moo_allochalfwordobj (moo_t* moo, const moo_oohw_t* ptr, moo_oow_t len)
{
return alloc_numeric_array (moo, ptr, len, MOO_OBJ_TYPE_HALFWORD, MOO_SIZEOF(moo_oohw_t), 0);
}
moo_oop_t moo_allocwordobj (moo_t* moo, const moo_oow_t* ptr, moo_oow_t len)
MOO_INLINE moo_oop_t moo_allocwordobj (moo_t* moo, const moo_oow_t* ptr, moo_oow_t len)
{
return alloc_numeric_array (moo, ptr, len, MOO_OBJ_TYPE_WORD, MOO_SIZEOF(moo_oow_t), 0);
}
@ -332,60 +332,11 @@ moo_oop_t moo_instantiate (moo_t* moo, moo_oop_class_t _class, const void* vptr,
break;
}
if (oop) MOO_OBJ_SET_CLASS (oop, (moo_oop_t)_class);
moo_poptmps (moo, tmp_count);
return oop;
}
/* TODO: ... */
moo_oop_t moo_instantiate2 (moo_t* moo, moo_oop_class_t _class, const void* vptr, moo_oow_t vlen, int ngc)
{
moo_oop_t oop;
moo_obj_type_t type;
moo_oow_t alloclen;
moo_oow_t tmp_count = 0;
MOO_ASSERT (moo, moo->_nil != MOO_NULL);
if (decode_spec (moo, _class, vlen, &type, &alloclen) <= -1)
if (oop)
{
moo->errnum = MOO_EINVAL;
return MOO_NULL;
MOO_OBJ_SET_CLASS (oop, (moo_oop_t)_class);
if (MOO_CLASS_SPEC_IS_IMMUTABLE(MOO_OOP_TO_SMOOI(_class->spec))) MOO_OBJ_SET_FLAGS_RDONLY (oop, 1);
}
moo_pushtmp (moo, (moo_oop_t*)&_class); tmp_count++;
/* TODO: support NGC */
switch (type)
{
case MOO_OBJ_TYPE_OOP:
/* [NOTE] vptr is not used for GC unsafety. read comment in moo_instantiate() */
oop = moo_allocoopobj (moo, alloclen);
break;
case MOO_OBJ_TYPE_CHAR:
oop = moo_alloccharobj (moo, vptr, alloclen);
break;
case MOO_OBJ_TYPE_BYTE:
oop = moo_allocbyteobj (moo, vptr, alloclen);
break;
case MOO_OBJ_TYPE_HALFWORD:
oop = moo_allochalfwordobj (moo, vptr, alloclen);
break;
case MOO_OBJ_TYPE_WORD:
oop = moo_allocwordobj (moo, vptr, alloclen);
break;
default:
moo->errnum = MOO_EINTERN;
oop = MOO_NULL;
break;
}
if (oop) MOO_OBJ_SET_CLASS (oop, _class);
moo_poptmps (moo, tmp_count);
return oop;
}
@ -411,6 +362,26 @@ moo_oop_t moo_instantiatewithtrailer (moo_t* moo, moo_oop_class_t _class, moo_oo
{
case MOO_OBJ_TYPE_OOP:
oop = moo_allocoopobjwithtrailer(moo, alloclen, trptr, trlen);
if (oop)
{
/* initialize named instance variables with default values */
if (_class->initv[0] != moo->_nil)
{
moo_oow_t i = MOO_OBJ_GET_SIZE(_class->initv[0]);
/* [NOTE] i don't deep-copy initial values.
* if you change the contents of compound values like arrays,
* it affects subsequent instantiation of the class.
* it's important that the compiler should mark compound initial
* values read-only. */
while (i > 0)
{
--i;
((moo_oop_oop_t)oop)->slot[i] = ((moo_oop_oop_t)_class->initv[0])->slot[i];
}
}
}
break;
default:
@ -424,7 +395,11 @@ moo_oop_t moo_instantiatewithtrailer (moo_t* moo, moo_oop_class_t _class, moo_oo
break;
}
if (oop) MOO_OBJ_SET_CLASS (oop, _class);
if (oop)
{
MOO_OBJ_SET_CLASS (oop, _class);
if (MOO_CLASS_SPEC_IS_IMMUTABLE(MOO_OOP_TO_SMOOI(_class->spec))) MOO_OBJ_SET_FLAGS_RDONLY (oop, 1);
}
moo_poptmps (moo, tmp_count);
return oop;
}

View File

@ -158,9 +158,6 @@ static moo_oop_t find_or_make_symbol (moo_t* moo, const moo_ooch_t* ptr, moo_oow
MOO_ASSERT (moo, tally < MOO_SMOOI_MAX);
moo->symtab->tally = MOO_SMOOI_TO_OOP(tally + 1);
moo->symtab->bucket->slot[index] = (moo_oop_t)symbol;
/* set RDONLY on a symbol */
MOO_OBJ_SET_FLAGS_RDONLY (symbol, 1);
}
return (moo_oop_t)symbol;