+added an "is" statement to detect type equality of a value.

This commit is contained in:
paladin-t 2015-12-11 13:04:23 +08:00
parent c3d64838ec
commit 8fdb8fe2d3
2 changed files with 113 additions and 36 deletions

View File

@ -1,4 +1,5 @@
Dec. 11 2015
Added an IS statement to detect type equality of a value
Added support to store a routine in a variable by CALL statement
Dec. 10 2015

View File

@ -36,6 +36,7 @@
#else /* _MSC_VER */
# include <stdint.h>
#endif /* _MSC_VER */
#include <limits.h>
#include <memory.h>
#include <assert.h>
#include <ctype.h>
@ -140,6 +141,8 @@ extern "C" {
/* Max length of a single symbol */
#define _SINGLE_SYMBOL_MAX_LENGTH 128
#define _META_LIST_MAX_DEPTH UINT_MAX
typedef int (* _common_compare)(void*, void*);
/* Container operation */
@ -590,27 +593,28 @@ typedef struct mb_interpreter_t {
} mb_interpreter_t;
/* Operations */
static const char _PRECEDE_TABLE[19][19] = { /* Operator priority table */
/* + - * / MOD ^ ( ) = > < >= <= == <> AND OR NOT NEG */
{ '>', '>', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* + */
{ '>', '>', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* - */
{ '>', '>', '>', '>', '>', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* * */
{ '>', '>', '>', '>', '>', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* / */
{ '>', '>', '<', '<', '>', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* MOD */
{ '>', '>', '>', '>', '>', '>', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* ^ */
{ '<', '<', '<', '<', '<', '<', '<', '=', ' ', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<' }, /* ( */
{ '>', '>', '>', '>', '>', '>', ' ', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* ) */
{ '<', '<', '<', '<', '<', '<', '<', ' ', '=', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<' }, /* = */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* > */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* < */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* >= */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* <= */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* == */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>' }, /* <> */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '<', '>' }, /* AND */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '<', '>' }, /* OR */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '>', '>' }, /* NOT */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '<', '<', '<', '=' } /* NEG */
static const char _PRECEDE_TABLE[20][20] = { /* Operator priority table */
/* + - * / MOD ^ ( ) = > < >= <= == <> AND OR NOT NEG IS */
{ '>', '>', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* + */
{ '>', '>', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* - */
{ '>', '>', '>', '>', '>', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* * */
{ '>', '>', '>', '>', '>', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* / */
{ '>', '>', '<', '<', '>', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* MOD */
{ '>', '>', '>', '>', '>', '>', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* ^ */
{ '<', '<', '<', '<', '<', '<', '<', '=', ' ', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<' }, /* ( */
{ '>', '>', '>', '>', '>', '>', ' ', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>' }, /* ) */
{ '<', '<', '<', '<', '<', '<', '<', ' ', '=', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<', '<' }, /* = */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>', '>' }, /* > */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>', '>' }, /* < */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>', '>' }, /* >= */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>', '>' }, /* <= */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>', '>' }, /* == */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', ' ', ' ', ' ', ' ', ' ', ' ', '>', '>', '>', '>', '>' }, /* <> */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '<', '>', '>' }, /* AND */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '<', '>', '>' }, /* OR */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>' }, /* NOT */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '<', '<', '<', '=', '<' }, /* NEG */
{ '<', '<', '<', '<', '<', '<', '<', '>', '>', '<', '<', '<', '<', '<', '<', '>', '>', '<', '>', '>' } /* IS */
};
static _object_t* _exp_assign = 0;
@ -1199,18 +1203,19 @@ static int _clone_to_dict(void* data, void* extra, _dict_t* coll);
#ifdef MB_ENABLE_CLASS
typedef int (* _class_scope_walker)(void*, void*, void*);
typedef int (* _class_meta_walker)(_class_t*, void*);
typedef bool_t (* _class_meta_walker)(_class_t*, void*, void*);
static void _init_class(mb_interpreter_t* s, _class_t* instance, char* n);
static void _begin_class(mb_interpreter_t* s);
static bool_t _end_class(mb_interpreter_t* s);
static void _unref_class(_ref_t* ref, void* data);
static void _destroy_class(_class_t* c);
static int _traverse_class(_class_t* c, _class_scope_walker scope_walker, _class_meta_walker meta_walker, int meta_depth, void* extra_data);
static bool_t _traverse_class(_class_t* c, _class_scope_walker scope_walker, _class_meta_walker meta_walker, unsigned meta_depth, bool_t meta_walk_on_self, void* extra_data, void* ret);
static bool_t _link_meta_class(mb_interpreter_t* s, _class_t* derived, _class_t* base);
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 _clone_clsss_field(void* data, void* extra, void* n);
static int _clone_class_meta_link(_class_t* meta, void* n);
static bool_t _clone_class_meta_link(_class_t* meta, void* n, void* ret);
static bool_t _is_class(_class_t* instance, void* m, void* ret);
#endif /* MB_ENABLE_CLASS */
static void _init_routine(mb_interpreter_t* s, _routine_t* routine, char* n);
static void _begin_routine(mb_interpreter_t* s);
@ -1352,6 +1357,7 @@ static int _core_not_equal(mb_interpreter_t* s, void** l);
static int _core_and(mb_interpreter_t* s, void** l);
static int _core_or(mb_interpreter_t* s, void** l);
static int _core_not(mb_interpreter_t* s, void** l);
static int _core_is(mb_interpreter_t* s, void** l);
static int _core_let(mb_interpreter_t* s, void** l);
static int _core_dim(mb_interpreter_t* s, void** l);
static int _core_if(mb_interpreter_t* s, void** l);
@ -1459,6 +1465,8 @@ static const _func_t _core_libs[] = {
{ "OR", _core_or },
{ "NOT", _core_not },
{ "IS", _core_is },
{ "LET", _core_let },
{ "DIM", _core_dim },
@ -2353,7 +2361,8 @@ bool_t _is_operator(mb_func_t op) {
(op == _core_greater_equal) ||
(op == _core_not_equal) ||
(op == _core_and) ||
(op == _core_or);
(op == _core_or) ||
(op == _core_is);
return result;
}
@ -2445,6 +2454,8 @@ int _get_priority_index(mb_func_t op) {
result = 17;
} else if(op == _core_neg) {
result = 18;
} else if(op == _core_is) {
result = 19;
} else {
mb_assert(0 && "Unknown operator.");
}
@ -4223,7 +4234,7 @@ int _gc_add_reachable(void* data, void* extra, void* ht) {
case _DT_CLASS:
if(!_ht_find(htable, &obj->data.instance->ref)) {
_ht_set_or_insert(htable, &obj->data.instance->ref, obj->data.instance);
_traverse_class(obj->data.instance, _gc_add_reachable, 0, 0, htable);
_traverse_class(obj->data.instance, _gc_add_reachable, 0, 0, false, htable, 0);
}
break;
@ -5300,32 +5311,43 @@ void _destroy_class(_class_t* c) {
safe_free(c);
}
int _traverse_class(_class_t* c, _class_scope_walker scope_walker, _class_meta_walker meta_walker, int meta_depth, void* extra_data) {
bool_t _traverse_class(_class_t* c, _class_scope_walker scope_walker, _class_meta_walker meta_walker, unsigned meta_depth, bool_t meta_walk_on_self, void* extra_data, void* ret) {
/* Traverse all fields of a class instance, and its meta class instances recursively as well */
int result = 0;
bool_t result = true;
_ls_node_t* node = 0;
_class_t* meta = 0;
mb_assert(c);
result++;
if(scope_walker) {
_HT_FOREACH(c->scope->var_dict, _do_nothing_on_object, scope_walker, extra_data);
}
if(meta_walk_on_self) {
if(meta_walker) {
result = meta_walker(c, extra_data, ret);
if(!result)
goto _exit;
}
}
node = c->meta_list ? c->meta_list->next : 0;
while(node) {
meta = (_class_t*)node->data;
if(meta_walker && meta_depth)
meta_walker(meta, extra_data);
result += _traverse_class(
if(meta_walker && meta_depth) {
result = meta_walker(meta, extra_data, ret);
if(!result) break;
}
result = _traverse_class(
meta,
scope_walker,
meta_walker, meta_depth ? meta_depth - 1 : 0,
extra_data
meta_walk_on_self,
extra_data, ret
);
if(!result) break;
node = node->next;
}
_exit:
return result;
}
@ -5411,15 +5433,28 @@ _exit:
return result;
}
int _clone_class_meta_link(_class_t* meta, void* n) {
bool_t _clone_class_meta_link(_class_t* meta, void* n, void* ret) {
/* Link meta class to a new instance */
_class_t* instance = (_class_t*)n;
mb_unrefvar(ret);
mb_assert(meta && n);
_link_meta_class(instance->ref.s, instance, meta);
return MB_FUNC_OK;
return true;
}
bool_t _is_class(_class_t* instance, void* m, void* ret) {
/* Detect whether a class instance is inherited from another */
_class_t* meta = (_class_t*)m;
bool_t* r = (bool_t*)ret;
mb_assert(instance && meta && ret);
*r = instance == meta;
return !(*r);
}
#endif /* MB_ENABLE_CLASS */
@ -5905,7 +5940,7 @@ int _clone_object(mb_interpreter_t* s, _object_t* obj, _object_t* tgt) {
tgt->data.instance = (_class_t*)mb_malloc(sizeof(_class_t));
_init_class(s, tgt->data.instance, mb_memdup(obj->data.instance->name, strlen(obj->data.instance->name)));
_push_scope_by_class(s, tgt->data.instance->scope);
_traverse_class(obj->data.instance, _clone_clsss_field, _clone_class_meta_link, 1, tgt->data.instance);
_traverse_class(obj->data.instance, _clone_clsss_field, _clone_class_meta_link, 1, false, tgt->data.instance, 0);
_pop_scope(s);
break;
@ -9250,6 +9285,44 @@ int _core_not(mb_interpreter_t* s, void** l) {
return result;
}
int _core_is(mb_interpreter_t* s, void** l) {
/* Operator IS */
int result = MB_FUNC_OK;
_object_t* fst = 0;
_object_t* scd = 0;
_object_t* val = 0;
bool_t is_a = 0;
mb_assert(s && l);
fst = (_object_t*)(((_tuple3_t*)(*l))->e1);
scd = (_object_t*)(((_tuple3_t*)(*l))->e2);
val = (_object_t*)(((_tuple3_t*)(*l))->e3);
if(!fst || !scd) {
_handle_error_on_obj(s, SE_RN_SYNTAX, 0, TON(l), MB_FUNC_ERR, _exit, result);
}
if(scd->type == _DT_TYPE) {
val->type = _DT_INT;
val->data.integer = (int_t)(_internal_type_to_public_type(fst->type) == scd->data.type);
} else {
#ifdef MB_ENABLE_CLASS
if(!_IS_CLASS(fst) || !_IS_CLASS(scd)) {
_handle_error_on_obj(s, SE_RN_CLASS_EXPECTED, 0, TON(l), MB_FUNC_ERR, _exit, result);
}
_traverse_class(fst->data.instance, 0, _is_class, _META_LIST_MAX_DEPTH, true, scd->data.instance, &is_a);
val->type = _DT_INT;
val->data.integer = (int_t)is_a;
#else /* MB_ENABLE_CLASS */
mb_unrefvar(is_a);
_handle_error_on_obj(s, SE_RN_NOT_SUPPORTED, 0, TON(l), MB_FUNC_ERR, _exit, result);
#endif /* MB_ENABLE_CLASS */
}
_exit:
return result;
}
int _core_let(mb_interpreter_t* s, void** l) {
/* LET statement */
int result = MB_FUNC_OK;
@ -11285,6 +11358,9 @@ int _std_print(mb_interpreter_t* s, void** l) {
case _DT_STRING: /* Fall through */
case _DT_VAR: /* Fall through */
case _DT_ARRAY: /* Fall through */
#ifdef MB_ENABLE_CLASS
case _DT_CLASS: /* Fall through */
#endif /* MB_ENABLE_CLASS */
case _DT_FUNC: /* Fall through */
case _DT_ROUTINE:
result = _calc_expression(s, &ast, &val_ptr);