+added a HASH meta method; +added a COMPARE meta method.

This commit is contained in:
paladin-t 2016-01-22 12:57:22 +08:00
parent e73dee7008
commit 5fe522bb47
2 changed files with 99 additions and 8 deletions

View File

@ -1,7 +1,11 @@
Jan. 22 2016
Added a HASH meta method to calculate the hash code of a class instance
Added a COMPARE meta method to compare two class instances
Jan. 21 2016 Jan. 21 2016
Fixed a referenced usertype comparison bug Fixed a referenced usertype comparison bug
Fixed a wrong memory copy bug with the PRINT statement Fixed a wrong memory copy bug with the PRINT statement
Added TOSTRING meta method to serialize a class instance Added a TOSTRING meta method to serialize a class instance
Improved type handling Improved type handling
Jan. 20 2016 Jan. 20 2016

View File

@ -420,6 +420,8 @@ typedef struct _class_t {
char* name; char* name;
_ls_node_t* meta_list; _ls_node_t* meta_list;
struct _running_context_t* scope; struct _running_context_t* scope;
struct _routine_t* hash;
struct _routine_t* compare;
void* userdata; void* userdata;
} _class_t; } _class_t;
#endif /* MB_ENABLE_CLASS */ #endif /* MB_ENABLE_CLASS */
@ -1468,6 +1470,7 @@ static void _unlink_meta_class(mb_interpreter_t* s, _class_t* derived);
static int _unlink_meta_instance(void* data, void* extra, _class_t* derived); static int _unlink_meta_instance(void* data, void* extra, _class_t* derived);
static int _clone_clsss_field(void* data, void* extra, void* n); static int _clone_clsss_field(void* data, void* extra, void* n);
static bool_t _clone_class_meta_link(_class_t* meta, void* n, void* ret); static bool_t _clone_class_meta_link(_class_t* meta, void* n, void* ret);
static int _search_class_meta_function(mb_interpreter_t* s, _class_t* instance, const char* n, _routine_t** f);
static bool_t _is_class(_class_t* instance, void* m, void* ret); static bool_t _is_class(_class_t* instance, void* m, void* ret);
static bool_t _add_class_meta_reachable(_class_t* meta, void* ht, void* ret); static bool_t _add_class_meta_reachable(_class_t* meta, void* ht, void* ret);
#ifdef MB_ENABLE_COLLECTION_LIB #ifdef MB_ENABLE_COLLECTION_LIB
@ -2210,6 +2213,9 @@ unsigned int _ht_hash_object(void* ht, void* d) {
_object_t* o = (_object_t*)d; _object_t* o = (_object_t*)d;
size_t i = 0; size_t i = 0;
unsigned int h = 0; unsigned int h = 0;
#ifdef MB_ENABLE_CLASS
_object_t val;
#endif /* MB_ENABLE_CLASS */
mb_assert(ht); mb_assert(ht);
@ -2220,7 +2226,27 @@ unsigned int _ht_hash_object(void* ht, void* d) {
break; break;
#ifdef MB_ENABLE_CLASS #ifdef MB_ENABLE_CLASS
/* TODO : Use customized "HASH" function for case _DT_CLASS */ case _DT_CLASS:
if(o->data.instance->hash) {
mb_interpreter_t* s = o->data.instance->ref.s;
_ls_node_t ast;
_ls_node_t* tmp = *
mb_value_t va[1];
mb_make_nil(va[0]);
memset(&ast, 0, sizeof(_ls_node_t));
if(_eval_routine(s, &tmp, va, 1, o->data.instance->hash, 0, 0) == MB_FUNC_OK) {
_MAKE_NIL(&val);
_public_value_to_internal_object(&s->running_context->intermediate_value, &val);
if(val.type != _DT_INT) {
int ignored = MB_FUNC_OK;
_handle_error_on_obj(s, SE_RN_INTEGER_EXPECTED, s->source_file, o, MB_FUNC_ERR, _exit, ignored);
}
o = &val;
}
}
goto _default;
#endif /* MB_ENABLE_CLASS */ #endif /* MB_ENABLE_CLASS */
case _DT_USERTYPE_REF: case _DT_USERTYPE_REF:
if(o->data.usertype_ref->hash) { if(o->data.usertype_ref->hash) {
@ -2231,6 +2257,9 @@ unsigned int _ht_hash_object(void* ht, void* d) {
} }
/* Fall through */ /* Fall through */
default: default:
#ifdef MB_ENABLE_CLASS
_default:
#endif /* MB_ENABLE_CLASS */
for(i = 0; i < sizeof(_raw_t); ++i) for(i = 0; i < sizeof(_raw_t); ++i)
h = 5 * h + o->data.raw[i]; h = 5 * h + o->data.raw[i];
result = h % self->array_size; result = h % self->array_size;
@ -2238,6 +2267,9 @@ unsigned int _ht_hash_object(void* ht, void* d) {
break; break;
} }
goto _exit; /* Avoid an unreferenced label warning */
_exit:
return result; return result;
} }
@ -2287,6 +2319,10 @@ int _ht_cmp_object(void* d1, void* d2) {
_object_t* o1 = (_object_t*)d1; _object_t* o1 = (_object_t*)d1;
_object_t* o2 = (_object_t*)d2; _object_t* o2 = (_object_t*)d2;
size_t i = 0; size_t i = 0;
#ifdef MB_ENABLE_CLASS
_routine_t* cmp = 0;
_object_t val;
#endif /* MB_ENABLE_CLASS */
if(o1->type < o2->type) if(o1->type < o2->type)
return -1; return -1;
@ -2297,7 +2333,30 @@ int _ht_cmp_object(void* d1, void* d2) {
case _DT_STRING: case _DT_STRING:
return _ht_cmp_string(o1->data.string, o2->data.string); return _ht_cmp_string(o1->data.string, o2->data.string);
#ifdef MB_ENABLE_CLASS #ifdef MB_ENABLE_CLASS
/* TODO : Use customized "COMPARE" function for case _DT_CLASS */ case _DT_CLASS:
if(o1->data.instance->compare) cmp = o1->data.instance->compare;
else if(o2->data.instance->compare) cmp = o2->data.instance->compare;
if(cmp) {
mb_interpreter_t* s = o1->data.instance->ref.s;
_ls_node_t ast;
_ls_node_t* tmp = &ast;
mb_value_t va[1];
mb_make_nil(va[0]);
_internal_object_to_public_value(o2, &va[0]);
memset(&ast, 0, sizeof(_ls_node_t));
if(_eval_routine(s, &tmp, va, 1, cmp, 0, 0) == MB_FUNC_OK) {
_MAKE_NIL(&val);
_public_value_to_internal_object(&s->running_context->intermediate_value, &val);
if(val.type != _DT_INT) {
int ignored = MB_FUNC_OK;
_handle_error_on_obj(s, SE_RN_INTEGER_EXPECTED, s->source_file, o1, MB_FUNC_ERR, _exit, ignored);
}
return (int)val.data.integer;
}
}
goto _default;
#endif /* MB_ENABLE_CLASS */ #endif /* MB_ENABLE_CLASS */
case _DT_USERTYPE_REF: case _DT_USERTYPE_REF:
if(o1->data.usertype_ref->cmp) if(o1->data.usertype_ref->cmp)
@ -2306,6 +2365,9 @@ int _ht_cmp_object(void* d1, void* d2) {
return o2->data.usertype_ref->cmp(o1->data.usertype_ref->ref.s, o1->data.usertype_ref->usertype, o2->data.usertype_ref->usertype); return o2->data.usertype_ref->cmp(o1->data.usertype_ref->ref.s, o1->data.usertype_ref->usertype, o2->data.usertype_ref->usertype);
/* Fall through */ /* Fall through */
default: default:
#ifdef MB_ENABLE_CLASS
_default:
#endif /* MB_ENABLE_CLASS */
for(i = 0; i < sizeof(_raw_t); ++i) { for(i = 0; i < sizeof(_raw_t); ++i) {
if(o1->data.raw[i] < o2->data.raw[i]) if(o1->data.raw[i] < o2->data.raw[i])
return -1; return -1;
@ -2316,6 +2378,9 @@ int _ht_cmp_object(void* d1, void* d2) {
break; break;
} }
goto _exit; /* Avoid an unreferenced label warning */
_exit:
return 0; return 0;
} }
@ -6440,6 +6505,22 @@ bool_t _clone_class_meta_link(_class_t* meta, void* n, void* ret) {
return true; return true;
} }
int _search_class_meta_function(mb_interpreter_t* s, _class_t* instance, const char* n, _routine_t** f) {
/* Search for a meta function with a specific name and assign to a member field */
_ls_node_t* node = _search_identifier_in_class(s, instance, n, 0, 0);
if(f) *f = 0;
if(node) {
_object_t* obj = (_object_t*)node->data;
if(obj && _IS_ROUTINE(obj)) {
if(f) *f = obj->data.routine;
return 1;
}
}
return 0;
}
bool_t _is_class(_class_t* instance, void* m, void* ret) { bool_t _is_class(_class_t* instance, void* m, void* ret) {
/* Detect whether a class instance is inherited from another */ /* Detect whether a class instance is inherited from another */
_class_t* meta = (_class_t*)m; _class_t* meta = (_class_t*)m;
@ -8450,8 +8531,10 @@ _retry:
goto _exit; goto _exit;
if(ast) { if(ast) {
obj = (_object_t*)ast->data; obj = ast ? (_object_t*)ast->data : 0;
if(_IS_EOS(obj)) { if(!obj) {
/* Do nothing */
} else if(_IS_EOS(obj)) {
ast = ast->next; ast = ast->next;
} else if(_IS_SEP(obj, ':')) { } else if(_IS_SEP(obj, ':')) {
skip_to_eoi = false; skip_to_eoi = false;
@ -12470,8 +12553,8 @@ int _core_class(mb_interpreter_t* s, void** l) {
last_inst = s->last_instance; last_inst = s->last_instance;
s->last_instance = instance; s->last_instance = instance;
/* Process meta prototype list */
if(_IS_FUNC(obj, _core_open_bracket)) { if(_IS_FUNC(obj, _core_open_bracket)) {
/* Process meta_list */
do { do {
ast = ast->next; ast = ast->next;
obj = (_object_t*)ast->data; obj = (_object_t*)ast->data;
@ -12498,8 +12581,8 @@ int _core_class(mb_interpreter_t* s, void** l) {
*l = ast; *l = ast;
/* Execute class body */
running = _push_scope_by_class(s, instance->scope); running = _push_scope_by_class(s, instance->scope);
do { do {
result = _execute_statement(s, (_ls_node_t**)l); result = _execute_statement(s, (_ls_node_t**)l);
if(result != MB_FUNC_OK && s->error_handler) { if(result != MB_FUNC_OK && s->error_handler) {
@ -12513,9 +12596,13 @@ int _core_class(mb_interpreter_t* s, void** l) {
if(!ast) break; if(!ast) break;
obj = (_object_t*)ast->data; obj = (_object_t*)ast->data;
} while(ast && !_IS_FUNC(obj, _core_endclass)); } while(ast && !_IS_FUNC(obj, _core_endclass));
_pop_scope(s, false); _pop_scope(s, false);
/* Search for meta functions */
_search_class_meta_function(s, instance, _CLASS_HASH_FUNC, &instance->hash);
_search_class_meta_function(s, instance, _CLASS_COMPARE_FUNC, &instance->compare);
/* Finished */
if(ast) { if(ast) {
_skip_to(s, &ast, _core_endclass, _DT_NIL); _skip_to(s, &ast, _core_endclass, _DT_NIL);