+added a REFLECT statement.
This commit is contained in:
parent
cc93e2ab7c
commit
acf5238d44
1
HISTORY
1
HISTORY
@ -1,4 +1,5 @@
|
||||
Jan. 15 2016
|
||||
Added a REFLECT statement
|
||||
Added an MB_ENABLE_USERTYPE_REF macro
|
||||
Added an MB_ENABLE_ARRAY_REF macro
|
||||
Fixed some crash bugs with invalid syntax
|
||||
|
Binary file not shown.
@ -21,7 +21,7 @@ Why are existing script interpreters so complex? Why is it so difficult to integ
|
||||
|
||||
## Introduction
|
||||
|
||||
MY-BASIC is a lightweight cross-platform easy extendable BASIC interpreter written in pure C with about 14,000 lines of source code. It supports structured grammar, and implements a style of OOP called [prototype-based programming](https://en.wikipedia.org/wiki/Prototype-based_programming) paradigm, furthermore it offers a functional programming ability with [lambda abstraction](https://en.wikipedia.org/wiki/Anonymous_function). Most advanced features are easily cuttable by modifying macros. It is aimed to be either an embeddable scripting language or a standalone interpreter. The core is pretty light; all in a C source file and an associated header file; simpleness of source file layout and tightness dependency make it feels extraordinarily tough. It's able to easily combine MY-BASIC with an existing project in C, C++, Objective-C, C#, etc. Script driven can make your projects more powerful, elegant and neat. It's also able to learn how to build an interpreter from scratch with MY-BASIC, or build your own dialect easily based on it.
|
||||
MY-BASIC is a lightweight cross-platform easy extendable BASIC interpreter written in pure C with about 15,000 lines of source code. It supports structured grammar, and implements a style of OOP called [prototype-based programming](https://en.wikipedia.org/wiki/Prototype-based_programming) paradigm, furthermore it offers a functional programming ability with [lambda abstraction](https://en.wikipedia.org/wiki/Anonymous_function). Most advanced features are easily cuttable by modifying macros. It is aimed to be either an embeddable scripting language or a standalone interpreter. The core is pretty light; all in a C source file and an associated header file; simpleness of source file layout and tightness dependency make it feels extraordinarily tough. It's able to easily combine MY-BASIC with an existing project in C, C++, Objective-C, C#, etc. Script driven can make your projects more powerful, elegant and neat. It's also able to learn how to build an interpreter from scratch with MY-BASIC, or build your own dialect easily based on it.
|
||||
|
||||
## Compatibility
|
||||
|
||||
|
141
core/my_basic.c
141
core/my_basic.c
@ -1418,6 +1418,10 @@ 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 _is_class(_class_t* instance, void* m, void* ret);
|
||||
static bool_t _add_class_meta_reachable(_class_t* meta, void* ht, void* ret);
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
static int _reflect_class_field(void* data, void* extra, void* d);
|
||||
#endif /* MB_ENABLE_COLLECTION_LIB */
|
||||
static _class_t* _reflect_string_to_class(mb_interpreter_t* s, const char* n, mb_value_t* arg);
|
||||
#endif /* MB_ENABLE_CLASS */
|
||||
static void _init_routine(mb_interpreter_t* s, _routine_t* routine, char* n, mb_routine_func_t f);
|
||||
static void _begin_routine(mb_interpreter_t* s);
|
||||
@ -1617,6 +1621,7 @@ static int _core_class(mb_interpreter_t* s, void** l);
|
||||
static int _core_endclass(mb_interpreter_t* s, void** l);
|
||||
static int _core_new(mb_interpreter_t* s, void** l);
|
||||
static int _core_var(mb_interpreter_t* s, void** l);
|
||||
static int _core_reflect(mb_interpreter_t* s, void** l);
|
||||
#endif /* MB_ENABLE_CLASS */
|
||||
#ifdef MB_ENABLE_LAMBDA
|
||||
static int _core_lambda(mb_interpreter_t* s, void** l);
|
||||
@ -1734,6 +1739,7 @@ static const _func_t _core_libs[] = {
|
||||
{ "ENDCLASS", _core_endclass },
|
||||
{ "NEW", _core_new },
|
||||
{ "VAR", _core_var },
|
||||
{ "REFLECT", _core_reflect },
|
||||
#endif /* MB_ENABLE_CLASS */
|
||||
|
||||
#ifdef MB_ENABLE_LAMBDA
|
||||
@ -6166,6 +6172,67 @@ bool_t _add_class_meta_reachable(_class_t* meta, void* ht, void* ret) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
int _reflect_class_field(void* data, void* extra, void* d) {
|
||||
/* Reflect each field of a class instance to a dictionary */
|
||||
int result = _OP_RESULT_NORMAL;
|
||||
_object_t* obj = 0;
|
||||
_var_t* var = 0;
|
||||
_routine_t* sub = 0;
|
||||
_dict_t* coll = (_dict_t*)d;
|
||||
mb_unrefvar(extra);
|
||||
|
||||
mb_assert(data && d);
|
||||
|
||||
obj = (_object_t*)data;
|
||||
if(_is_internal_object(obj))
|
||||
goto _exit;
|
||||
switch(obj->type) {
|
||||
case _DT_VAR:
|
||||
var = (_var_t*)obj->data.variable;
|
||||
if(!_ht_find(coll->dict, var->name)) {
|
||||
mb_value_t kv, vv;
|
||||
mb_make_string(kv, var->name);
|
||||
_internal_object_to_public_value(obj, &vv);
|
||||
_set_dict(coll, &kv, &vv, 0, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
case _DT_ROUTINE:
|
||||
sub = (_routine_t*)obj->data.routine;
|
||||
if(!_ht_find(coll->dict, sub->name)) {
|
||||
mb_value_t kv, vv;
|
||||
mb_make_string(kv, sub->name);
|
||||
mb_make_type(vv, _internal_type_to_public_type(obj->type));
|
||||
_set_dict(coll, &kv, &vv, 0, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
default: /* Do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
_exit:
|
||||
return result;
|
||||
}
|
||||
#endif /* MB_ENABLE_COLLECTION_LIB */
|
||||
|
||||
_class_t* _reflect_string_to_class(mb_interpreter_t* s, const char* n, mb_value_t* arg) {
|
||||
/* Reflect a class instance from a string */
|
||||
_ls_node_t* cs = 0;
|
||||
_object_t* c = 0;
|
||||
|
||||
cs = _search_identifier_in_scope_chain(s, 0, n, 0, 0, 0);
|
||||
if(!cs || !cs->data) return 0;
|
||||
c = (_object_t*)cs->data;
|
||||
if(!c) return 0;
|
||||
c = _GET_CLASS(c);
|
||||
if(!c) return 0;
|
||||
if(arg) _internal_object_to_public_value(c, arg);
|
||||
|
||||
return c->data.instance;
|
||||
}
|
||||
#endif /* MB_ENABLE_CLASS */
|
||||
|
||||
void _init_routine(mb_interpreter_t* s, _routine_t* routine, char* n, mb_routine_func_t f) {
|
||||
@ -7104,7 +7171,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_strdup(obj->data.instance->name, 0));
|
||||
_push_scope_by_class(s, tgt->data.instance->scope);
|
||||
_traverse_class(obj->data.instance, _clone_clsss_field, _clone_class_meta_link, 1, false, tgt->data.instance, 0);
|
||||
_traverse_class(obj->data.instance, _clone_clsss_field, _clone_class_meta_link, _META_LIST_MAX_DEPTH, false, tgt->data.instance, 0);
|
||||
_pop_scope(s, false);
|
||||
|
||||
break;
|
||||
@ -12116,8 +12183,7 @@ int _core_new(mb_interpreter_t* s, void** l) {
|
||||
_object_t obj;
|
||||
_object_t tgt;
|
||||
mb_value_t ret;
|
||||
_ls_node_t* cs = 0;
|
||||
_object_t* c = 0;
|
||||
_class_t* instance = 0;
|
||||
|
||||
mb_assert(s && l);
|
||||
|
||||
@ -12133,14 +12199,9 @@ int _core_new(mb_interpreter_t* s, void** l) {
|
||||
switch(arg.type) {
|
||||
case MB_DT_STRING:
|
||||
arg.value.string = mb_strupr(arg.value.string);
|
||||
cs = _search_identifier_in_scope_chain(s, 0, arg.value.string, 0, 0, 0);
|
||||
if(!cs || !cs->data) goto _default;
|
||||
c = (_object_t*)cs->data;
|
||||
if(!c) goto _default;
|
||||
c = _GET_CLASS(c);
|
||||
if(!c) goto _default;
|
||||
_internal_object_to_public_value(c, &arg);
|
||||
_ref(&c->data.instance->ref, c->data.instance);
|
||||
if((instance = _reflect_string_to_class(s, arg.value.string, &arg)) == 0)
|
||||
goto _default;
|
||||
_ref(&instance->ref, instance);
|
||||
/* Fall through */
|
||||
case MB_DT_CLASS:
|
||||
_public_value_to_internal_object(&arg, &obj);
|
||||
@ -12183,6 +12244,63 @@ _exit:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int _core_reflect(mb_interpreter_t* s, void** l) {
|
||||
/* REFLECT statement */
|
||||
#ifdef MB_ENABLE_COLLECTION_LIB
|
||||
int result = MB_FUNC_OK;
|
||||
mb_value_t arg;
|
||||
_object_t obj;
|
||||
mb_value_t ret;
|
||||
_class_t* instance = 0;
|
||||
_dict_t* coll = 0;
|
||||
|
||||
mb_assert(s && l);
|
||||
|
||||
mb_make_nil(ret);
|
||||
|
||||
mb_check(mb_attempt_func_begin(s, l));
|
||||
|
||||
mb_check(mb_pop_value(s, l, &arg));
|
||||
|
||||
mb_check(mb_attempt_func_end(s, l));
|
||||
|
||||
_MAKE_NIL(&obj);
|
||||
switch(arg.type) {
|
||||
case MB_DT_STRING:
|
||||
arg.value.string = mb_strupr(arg.value.string);
|
||||
if((instance = _reflect_string_to_class(s, arg.value.string, &arg)) == 0)
|
||||
goto _default;
|
||||
_ref(&instance->ref, instance);
|
||||
/* Fall through */
|
||||
case MB_DT_CLASS:
|
||||
_public_value_to_internal_object(&arg, &obj);
|
||||
coll = _create_dict(s);
|
||||
_traverse_class(obj.data.instance, _reflect_class_field, 0, _META_LIST_MAX_DEPTH, false, coll, 0);
|
||||
ret.type = MB_DT_DICT;
|
||||
ret.value.dict = coll;
|
||||
|
||||
break;
|
||||
default:
|
||||
_default:
|
||||
_handle_error_on_obj(s, SE_RN_CLASS_EXPECTED, 0, TON(l), MB_FUNC_ERR, _exit, result);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mb_check(mb_push_value(s, l, ret));
|
||||
|
||||
_exit:
|
||||
_assign_public_value(&arg, 0);
|
||||
|
||||
return result;
|
||||
#else /* MB_ENABLE_COLLECTION_LIB */
|
||||
mb_unrefvar(s);
|
||||
mb_unrefvar(l);
|
||||
|
||||
return MB_FUNC_ERR;
|
||||
#endif /* MB_ENABLE_COLLECTION_LIB */
|
||||
}
|
||||
#endif /* MB_ENABLE_CLASS */
|
||||
|
||||
#ifdef MB_ENABLE_LAMBDA
|
||||
@ -13763,6 +13881,7 @@ int _coll_get(mb_interpreter_t* s, void** l) {
|
||||
case MB_DT_CLASS:
|
||||
_public_value_to_internal_object(&coi, &ocoi);
|
||||
mb_check(mb_pop_string(s, l, &field));
|
||||
field = mb_strupr(field);
|
||||
fnode = _search_identifier_in_class(s, ocoi.data.instance, field, 0, 0);
|
||||
if(fnode && fnode->data) {
|
||||
fobj = (_object_t*)fnode->data;
|
||||
|
@ -191,6 +191,9 @@ extern "C" {
|
||||
#ifndef mb_make_nil
|
||||
# define mb_make_nil(__v) do { (__v).value.integer = 0; (__v).type = MB_DT_NIL; } while(0)
|
||||
#endif /* mb_make_nil */
|
||||
#ifndef mb_make_type
|
||||
# define mb_make_type(__v, __d) do { (__v).value.type = (__d); (__v).type = MB_DT_TYPE; } while(0)
|
||||
#endif /* mb_make_type */
|
||||
#ifndef mb_make_int
|
||||
# define mb_make_int(__v, __d) do { (__v).value.integer = (__d); (__v).type = MB_DT_INT; } while(0)
|
||||
#endif /* mb_make_int */
|
||||
@ -203,9 +206,11 @@ extern "C" {
|
||||
#ifndef mb_make_usertype
|
||||
# define mb_make_usertype(__v, __d) do { (__v).value.usertype = (__d); (__v).type = MB_DT_USERTYPE; } while(0)
|
||||
#endif /* mb_make_usertype */
|
||||
#ifndef mb_make_usertype_ref
|
||||
# define mb_make_usertype_ref(__v, __d) do { (__v).value.usertype_ref = (__d); (__v).type = MB_DT_USERTYPE_REF; } while(0)
|
||||
#endif /* mb_make_usertype_ref */
|
||||
#ifdef MB_ENABLE_USERTYPE_REF
|
||||
# ifndef mb_make_usertype_ref
|
||||
# define mb_make_usertype_ref(__v, __d) do { (__v).value.usertype_ref = (__d); (__v).type = MB_DT_USERTYPE_REF; } while(0)
|
||||
# endif /* mb_make_usertype_ref */
|
||||
#endif /* MB_ENABLE_USERTYPE_REF */
|
||||
#ifndef mb_make_array
|
||||
# define mb_make_array(__v, __d) do { (__v).value.array = (__d); (__v).type = MB_DT_ARRAY; } while(0)
|
||||
#endif /* mb_make_array */
|
||||
@ -219,7 +224,7 @@ extern "C" {
|
||||
#endif /* MB_ENABLE_COLLECTION_LIB */
|
||||
|
||||
#ifndef mb_int_val
|
||||
# define mb_int_val(__v, __i) do { if((__v).type == MB_DT_INT) (__i) = (__v).value.integer; else if((__v).type == MB_DT_REAL) (__i) = (int_t)((__v).value.float_point); else (__i) = ~((int_t)0); } while(0)
|
||||
# define mb_int_val(__v, __d) do { if((__v).type == MB_DT_INT) (__d) = (__v).value.integer; else if((__v).type == MB_DT_REAL) (__d) = (int_t)((__v).value.float_point); else (__d) = ~((int_t)0); } while(0)
|
||||
#endif /* mb_int_val */
|
||||
|
||||
#ifndef MB_CODES
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user