From 08e54cb524b50f6f25ef455e7af28278812e913a Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Mon, 24 Apr 2017 14:32:21 +0000 Subject: [PATCH] enhanced the compiler to handle default initial values for class instance variables --- moo/kernel/Class.moo | 6 +- moo/lib/comp.c | 215 +++++++++++++++++++++++-------------------- moo/lib/moo-prv.h | 6 +- moo/lib/moo.h | 14 +-- moo/lib/obj.c | 7 +- 5 files changed, 133 insertions(+), 115 deletions(-) diff --git a/moo/kernel/Class.moo b/moo/kernel/Class.moo index bf04d90..10560c4 100644 --- a/moo/kernel/Class.moo +++ b/moo/kernel/Class.moo @@ -4,8 +4,10 @@ ## class(#pointer) Class(Apex) { - var spec, selfspec, superclass, subclasses, name, modname, instvars. - var classvars, classinstvars, pooldics, instmthdic, classmthdic, nsdic, cdic, trsize, initv. + var spec, selfspec, superclass, subclasses, name, modname. + var instvars, classinstvars, classvars, pooldics. + var instmthdic, classmthdic, nsdic, cdic. + var trsize, initv, initv_ci. method(#class) basicNew { diff --git a/moo/lib/comp.c b/moo/lib/comp.c index 83157d9..1464831 100644 --- a/moo/lib/comp.c +++ b/moo/lib/comp.c @@ -55,12 +55,12 @@ enum class_mod_t enum var_type_t { - /* NEVER Change the order and the value of 3 items below. - * moo->c->cls.var relies on them. */ + /* == NEVER CHANGE THIS ORDER OF 3 ITEMS BELOW == + * moo->c->cls.var and some iterations rely on them. */ VAR_INSTANCE = 0, - VAR_CLASS = 1, - VAR_CLASSINST = 2, - /* NEVER Change the order and the value of 3 items above. */ + VAR_CLASSINST = 1, + VAR_CLASS = 2, + /* == NEVER CHANGE THIS ORDER OF 3 ITEMS ABOVE == */ VAR_GLOBAL, VAR_ARGUMENT, @@ -2604,11 +2604,11 @@ static moo_ooi_t find_class_level_variable (moo_t* moo, moo_oop_class_t self, co * the loop here assumes that the class has the following * fields in the order shown below: * instvars - * classvars * classinstvars + * classvars */ vv = &self->instvars; - for (index = VAR_INSTANCE; index <= VAR_CLASSINST; index++) + for (index = VAR_INSTANCE; index <= VAR_CLASS; index++) { v = vv[index]; hs.ptr = v->slot; @@ -2632,7 +2632,7 @@ static moo_ooi_t find_class_level_variable (moo_t* moo, moo_oop_class_t self, co { /* the class definition is not available yet. * find the variable in the compiler's own list */ - for (index = VAR_INSTANCE; index <= VAR_CLASSINST; index++) + for (index = VAR_INSTANCE; index <= VAR_CLASS; index++) { if (find_word_in_string(&moo->c->cls.var[index].str, name, &pos) >= 0) { @@ -2656,7 +2656,7 @@ static moo_ooi_t find_class_level_variable (moo_t* moo, moo_oop_class_t self, co * classinstvars */ vv = &((moo_oop_class_t)super)->instvars; - for (index = VAR_INSTANCE; index <= VAR_CLASSINST; index++) + for (index = VAR_INSTANCE; index <= VAR_CLASS; index++) { v = vv[index]; hs.ptr = v->slot; @@ -2701,6 +2701,11 @@ done: pos += MOO_CLASS_SPEC_NAMED_INSTVAR(spec); break; + case VAR_CLASSINST: + spec = MOO_OOP_TO_SMOOI(((moo_oop_class_t)super)->selfspec); + pos += MOO_CLASS_SELFSPEC_CLASSINSTVAR(spec); + break; + case VAR_CLASS: /* [NOTE] * no adjustment is needed. @@ -2710,11 +2715,6 @@ done: * class instance variables that can be potentially * placed before the class variables. */ break; - - case VAR_CLASSINST: - spec = MOO_OOP_TO_SMOOI(((moo_oop_class_t)super)->selfspec); - pos += MOO_CLASS_SELFSPEC_CLASSINSTVAR(spec); - break; } } @@ -3824,17 +3824,6 @@ static int get_variable_info (moo_t* moo, const moo_oocs_t* name, const moo_iolo } break; - case VAR_CLASS: - /* a class variable can be accessed by both instance methods and class methods */ - MOO_ASSERT (moo, var->cls != MOO_NULL); - MOO_ASSERT (moo, MOO_CLASSOF(moo, var->cls) == moo->_class); - - /* increment the position by the number of class instance variables - * as the class variables are placed after the class instance variables */ - var->pos += MOO_CLASS_NAMED_INSTVARS + - MOO_CLASS_SELFSPEC_CLASSINSTVAR(MOO_OOP_TO_SMOOI(var->cls->selfspec)); - break; - case VAR_CLASSINST: /* class instance variable can be accessed by only class methods */ if (moo->c->mth.type == MOO_METHOD_INSTANCE) @@ -3850,6 +3839,17 @@ static int get_variable_info (moo_t* moo, const moo_oocs_t* name, const moo_iolo var->pos += MOO_CLASS_NAMED_INSTVARS; break; + case VAR_CLASS: + /* a class variable can be accessed by both instance methods and class methods */ + MOO_ASSERT (moo, var->cls != MOO_NULL); + MOO_ASSERT (moo, MOO_CLASSOF(moo, var->cls) == moo->_class); + + /* increment the position by the number of class instance variables + * as the class variables are placed after the class instance variables */ + var->pos += MOO_CLASS_NAMED_INSTVARS + + MOO_CLASS_SELFSPEC_CLASSINSTVAR(MOO_OOP_TO_SMOOI(var->cls->selfspec)); + break; + default: /* internal error - it must not happen */ moo->errnum = MOO_EINTERN; @@ -6233,12 +6233,71 @@ static int compile_method_definition (moo_t* moo) return 0; } +static int make_default_initial_values (moo_t* moo, var_type_t var_type) +{ + moo_oow_t initv_count; + + MOO_ASSERT (moo, var_type == VAR_INSTANCE || var_type == VAR_CLASSINST); + MOO_ASSERT (moo, VAR_INSTANCE == 0); + MOO_ASSERT (moo, VAR_CLASSINST == 1); + + initv_count = moo->c->cls.var[var_type].initv_count; + if (moo->c->cls.super_oop != moo->_nil && ((moo_oop_class_t)moo->c->cls.super_oop)->initv[var_type] != moo->_nil) + { + initv_count += MOO_OBJ_GET_SIZE(((moo_oop_class_t)moo->c->cls.super_oop)->initv[var_type]); + } + if (initv_count > 0) + { + moo_oow_t i, j = 0; + moo_oop_t tmp; + + /* [NOTE] + * if some elements at the back of a class definition are lacking default values, + * initv_count is less than total_count. + * in the following case(no inheritance for simplicity): + * class ... { var a, b := 10, c. } + * initv_count is 1 whereas total_count is 3. */ + MOO_ASSERT (moo, initv_count <= moo->c->cls.var[var_type].total_count); + + tmp = moo_instantiate (moo, moo->_array, MOO_NULL, moo->c->cls.var[var_type].total_count); + if (!tmp) return -1; + + if (initv_count > moo->c->cls.var[var_type].initv_count) + { + /* handle default values defined in the superclass chain. + * i merge them into a single array for convenience and + * efficiency of object instantiation by moo_instantiate(). + * it can avoid looking up superclasses upon instantiaion */ + moo_oop_oop_t initv; + moo_oow_t super_count; + + MOO_ASSERT (moo, moo->c->cls.super_oop != moo->_nil); + super_count = initv_count - moo->c->cls.var[var_type].initv_count; + initv = (moo_oop_oop_t)((moo_oop_class_t)moo->c->cls.super_oop)->initv[var_type]; + MOO_ASSERT (moo, MOO_CLASSOF(moo, initv) == moo->_array); + for (i = 0; i < super_count; i++) + { + ((moo_oop_oop_t)tmp)->slot[j++] = initv->slot[i]; + } + } + + for (i = 0; i < moo->c->cls.var[var_type].initv_count; i++) + { + ((moo_oop_oop_t)tmp)->slot[j++] = moo->c->cls.var[var_type].initv[i]; + } + + moo->c->cls.self_oop->initv[var_type] = tmp; + } + + return 0; +} + static int make_defined_class (moo_t* moo) { /* this function make a class object with no functions/methods */ moo_oop_t tmp; - moo_oow_t spec, self_spec, initv_count; + moo_oow_t spec, self_spec; int just_made = 0; spec = MOO_CLASS_SPEC_MAKE (moo->c->cls.var[VAR_INSTANCE].total_count, @@ -6325,91 +6384,47 @@ static int make_defined_class (moo_t* moo) if (!tmp) return -1; moo->c->cls.self_oop->mthdic[MOO_METHOD_CLASS] = (moo_oop_set_t)tmp; + /* store the default intial values for instance variables */ + if (make_default_initial_values (moo, VAR_INSTANCE) <= -1) return -1; - /* create an array of default initial values for instance variables */ - initv_count = moo->c->cls.var[VAR_INSTANCE].initv_count; - if (moo->c->cls.super_oop != moo->_nil && ((moo_oop_class_t)moo->c->cls.super_oop)->initv != moo->_nil) + /* store the default intial values for class instance variables */ + if (make_default_initial_values (moo, VAR_CLASSINST) <= -1) return -1; + if (moo->c->cls.self_oop->initv[VAR_CLASSINST] != moo->_nil) { - initv_count += MOO_OBJ_GET_SIZE(((moo_oop_class_t)moo->c->cls.super_oop)->initv); - } - if (initv_count > 0) - { - moo_oow_t i, j = 0; + moo_oow_t i, initv_count; + moo_oop_oop_t initv; - /* [NOTE] - * if some elements at the back of a class definition are lacking default values, - * initv_count is less than total_count. - * in the following case(no inheritance for simplicity): - * class ... { var a, b := 10, c. } - * initv_count is 1 whereas total_count is 3. */ - MOO_ASSERT (moo, initv_count <= moo->c->cls.var[VAR_INSTANCE].total_count); + /* apply the default initial values for class instance variables to this class now */ + initv = (moo_oop_oop_t)moo->c->cls.self_oop->initv[VAR_CLASSINST]; + MOO_ASSERT (moo, MOO_CLASSOF(moo, initv) == moo->_array); + initv_count = MOO_OBJ_GET_SIZE(initv); - tmp = moo_instantiate (moo, moo->_array, MOO_NULL, moo->c->cls.var[VAR_INSTANCE].total_count); - if (!tmp) return -1; - - if (initv_count > moo->c->cls.var[VAR_INSTANCE].initv_count) + for (i = 0; i < initv_count; i++) { - /* handle default values defined in the superclass chain. - * i merge them into a single array for convenience and - * efficiency of object instantiation by moo_instantiate(). - * it can avoid looking up superclasses upon instantiaion */ - moo_oop_oop_t initv; - moo_oow_t super_count; - - MOO_ASSERT (moo, moo->c->cls.super_oop != moo->_nil); - super_count = initv_count - moo->c->cls.var[VAR_INSTANCE].initv_count; - initv = (moo_oop_oop_t)((moo_oop_class_t)moo->c->cls.super_oop)->initv; - MOO_ASSERT (moo, MOO_CLASSOF(moo, initv) == moo->_array); - for (i = 0; i < super_count; i++) - { - ((moo_oop_oop_t)tmp)->slot[j++] = initv->slot[i]; - } + moo->c->cls.self_oop->slot[i] = initv->slot[i]; } - - for (i = 0; i < moo->c->cls.var[VAR_INSTANCE].initv_count; i++) - { - ((moo_oop_oop_t)tmp)->slot[j++] = moo->c->cls.var[VAR_INSTANCE].initv[i]; - } - - moo->c->cls.self_oop->initv = tmp; } /* initialize class variables with default initial values */ - initv_count = moo->c->cls.var[VAR_CLASS].initv_count; - if (initv_count > 0) + if (moo->c->cls.var[VAR_CLASS].initv_count > 0) { - moo_oow_t i, j; + moo_oow_t i, j, initv_count; + + initv_count = moo->c->cls.var[VAR_CLASS].initv_count; + /* name instance variables and class instance variables are placed - * in the front part. let's skip them */ - #if 0 - /* this part is almost identical to the actual code after #else - * i keep this for demonstration purpose only */ - j = MOO_CLASS_NAMED_INSTVARS + moo->c->cls.var[VAR_CLASSINST].total_count; - MOO_ASSERT (moo, j + initv_count < MOO_OBJ_GET_SIZE(moo->c->cls.self_oop)); - for (i = 0; i < initv_count; i++) - { - ((moo_oop_oop_t)moo->c->cls.self_oop)->slot[j++] = moo->c->cls.var[VAR_CLASS].initv[i]; - } - #else + * in the front part. set j such that they can be skipped. */ j = moo->c->cls.var[VAR_CLASSINST].total_count; + + MOO_ASSERT (moo, MOO_CLASS_NAMED_INSTVARS + j + initv_count <= MOO_OBJ_GET_SIZE(moo->c->cls.self_oop)); for (i = 0; i < initv_count; i++) { - moo->c->cls.self_oop->slot[j++] = moo->c->cls.var[VAR_CLASS].initv[i]; + /* ((moo_oop_oop_t)moo->c->cls.self_oop)->slot[MOO_CLASS_NAMED_INSTVARS + j] = moo->c->cls.var[VAR_CLASS].initv[i]; */ + moo->c->cls.self_oop->slot[j] = moo->c->cls.var[VAR_CLASS].initv[i]; + j++; } - #endif } -#if 0 - /* create an array of default values for class instance variables */ - initv_count = moo->c->cls.var[VAR_CLASSINST].initv_count; - if (moo->c->cls.super_oop != moo->_nil && ((moo_oop_class_t)moo->c->cls.super_oop)->initv_ci != moo->_nil) - { - initv_count += MOO_OBJ_GET_SIZE(((moo_oop_class_t)moo->c->cls.super_oop)->initv_ci); - } -#endif - -/* TODO: class instance variables ... */ - /* [NOTE] don't create a dictionary on the nsdic. keep it to be nil. * add_nsdic_to_class() instantiates a dictionary if necessary. */ @@ -6819,18 +6834,18 @@ static int __compile_class_definition (moo_t* moo, int extend) GET_TOKEN (moo); if (compile_class_level_variables_vbar(moo, VAR_INSTANCE) <= -1) return -1; } - else if (is_token_binary_selector(moo, VOCA_VBAR_PLUS)) - { - /* class variables |+ a b c | */ - GET_TOKEN (moo); - if (compile_class_level_variables_vbar(moo, VAR_CLASS) <= -1) return -1; - } else if (is_token_binary_selector(moo, VOCA_VBAR_ASTER)) { /* class instance variables |* a b c | */ GET_TOKEN (moo); if (compile_class_level_variables_vbar(moo, VAR_CLASSINST) <= -1) return -1; } + else if (is_token_binary_selector(moo, VOCA_VBAR_PLUS)) + { + /* class variables |+ a b c | */ + GET_TOKEN (moo); + if (compile_class_level_variables_vbar(moo, VAR_CLASS) <= -1) return -1; + } else if (is_token_word(moo, VOCA_DCL) || is_token_word(moo, VOCA_VAR) || is_token_word(moo, VOCA_VARIABLE)) { /* variable declaration */ diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index 78696ac..664d794 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -170,7 +170,7 @@ * type of the spec field in the class object. */ /* -#define MOO_MAX_NAMED_INSTVARS \ +#define MOO_MAX_NAMED_INSTVARSVARS \ MOO_BITS_MAX(moo_oow_t, MOO_OOW_BITS - MOO_OOP_TAG_BITS_LO - (MOO_OBJ_FLAGS_TYPE_BITS + 1) - 1) */ #define MOO_MAX_NAMED_INSTVARS \ @@ -452,8 +452,8 @@ struct moo_compiler_t /* instance variable, class variable, class instance variable * var[0] - named instance variables - * var[1] - class variables - * var[2] - class instance variables */ + * var[1] - class instance variables + * var[2] - class variables */ struct { moo_oocs_t str; /* long string containing all variables declared delimited by a space */ diff --git a/moo/lib/moo.h b/moo/lib/moo.h index 3f7cd0e..59f9d7f 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -174,8 +174,8 @@ typedef struct moo_obj_word_t* moo_oop_word_t; enum moo_method_type_t { - MOO_METHOD_INSTANCE, - MOO_METHOD_CLASS, + MOO_METHOD_INSTANCE = 0, + MOO_METHOD_CLASS = 1, /* --------------------------- */ MOO_METHOD_TYPE_COUNT @@ -485,7 +485,7 @@ struct moo_set_t moo_oop_oop_t bucket; /* Array */ }; -#define MOO_CLASS_NAMED_INSTVARS 16 +#define MOO_CLASS_NAMED_INSTVARS 17 typedef struct moo_class_t moo_class_t; typedef struct moo_class_t* moo_oop_class_t; struct moo_class_t @@ -499,12 +499,12 @@ struct moo_class_t moo_oop_t subclasses; /* Array of subclasses */ moo_oop_char_t name; /* Symbol */ - moo_oop_t modname; /* Symbol if importing a module. nil if not. */ + moo_oop_t modname; /* Symbol if importing a module. nil if not. */ /* == NEVER CHANGE THIS ORDER OF 3 ITEMS BELOW == */ moo_oop_char_t instvars; /* String */ - moo_oop_char_t classvars; /* String */ moo_oop_char_t classinstvars; /* String */ + moo_oop_char_t classvars; /* String */ /* == NEVER CHANGE THE ORDER OF 3 ITEMS ABOVE == */ moo_oop_char_t pooldics; /* String - pool dictionaries imported */ @@ -517,7 +517,9 @@ struct moo_class_t moo_oop_set_t cdic; /* constant dictionary */ moo_oop_t trsize; /* trailer size for new instances */ - moo_oop_t initv; /* instial values for new instances */ + /* [0] - initial values for instance variables of new instances + * [1] - initial values for class instance variables */ + moo_oop_t initv[2]; /* indexed part afterwards */ moo_oop_t slot[1]; /* class instance variables and class variables. */ diff --git a/moo/lib/obj.c b/moo/lib/obj.c index 0ed5c7e..d6b34c0 100644 --- a/moo/lib/obj.c +++ b/moo/lib/obj.c @@ -275,10 +275,9 @@ moo_oop_t moo_instantiate (moo_t* moo, moo_oop_class_t _class, const void* vptr, if (oop) { /* initialize named instance variables with default values */ - if (_class->initv != moo->_nil) + if (_class->initv[0] != moo->_nil) { - - moo_oow_t i = MOO_OBJ_GET_SIZE(_class->initv); + 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, @@ -288,7 +287,7 @@ moo_oop_t moo_instantiate (moo_t* moo, moo_oop_class_t _class, const void* vptr, while (i > 0) { --i; - ((moo_oop_oop_t)oop)->slot[i] = ((moo_oop_oop_t)_class->initv)->slot[i]; + ((moo_oop_oop_t)oop)->slot[i] = ((moo_oop_oop_t)_class->initv[0])->slot[i]; } } }