-
Notifications
You must be signed in to change notification settings - Fork 118
Defining a class in C
It's possible to define class, add member variable and routine from C side. There's no difference between a class prototype defined in BASIC and in C, a C class can link a BASIC class as meta class, and vice versa.
Assuming we have a NATIVE_METHOD
function defined in C for later use:
static int _native_method(struct mb_interpreter_t* s, void** l, mb_value_t* va, unsigned ca, void* r, mb_has_routine_arg_func_t has, mb_pop_routine_arg_func_t pop) {
int result = MB_FUNC_OK;
mb_value_t val;
unsigned ia = 0;
mb_assert(s && l);
mb_check(mb_attempt_open_bracket(s, l));
mb_make_nil(val);
if(has(s, l, va, ca, &ia, r)) {
mb_check(pop(s, l, va, ca, &ia, r, &val));
}
mb_check(mb_attempt_close_bracket(s, l));
printf("%d\n", val.value.integer);
return result;
}
A routine of a class instance may be invoked not only from the BASIC side, but also from the native side. But the mb_has_arg
and mb_pop_*
functions are dedicated to manipulate arguments at BASIC side. So for this case, the proper way is using the mb_has_routine_arg_func_t has
and mb_pop_routine_arg_func_t pop
instead as equivalents respectively to mb_has_arg
and mb_pop_value
. You don't need to care about the parameters _value_t* va
, unsigned ca
, unsigned ia
and void* r
, the only places you have to write them is passing to them has
and pop
. All the rest parts of a native method routine are similar to regular int (* mb_func_t)(struct mb_interpreter_t*, void**)
signatured functions, including the usage of mb_attempt_func_begin
, mb_attempt_func_end
, mb_attempt_open_bracket
, mb_attempt_close_bracket
and mb_push_*
.
There are two functions mb_begin_class
, mb_end_class
correspond to the CLASS
/ENDCLASS
statements which can be used to declare a class in C; and use mb_add_var
and mb_set_routine
to set member of a class. For example:
static int _do_something_in_c(struct mb_interpreter_t* s, void** l) {
int result = MB_FUNC_OK;
mb_value_t clz;
mb_value_t script_base;
mb_value_t* metas[1];
mb_value_t cval;
mb_assert(s && l);
mb_check(mb_attempt_open_bracket(s, l));
mb_check(mb_attempt_close_bracket(s, l));
mb_make_nil(script_base);
mb_check(mb_get_value_by_name(s, l, "SCRIPT_BASE", &script_base)); /* Get the "SCRIPT_BASE" class from BASIC */
metas[0] = &script_base;
mb_make_nil(clz);
mb_check(mb_begin_class(s, l, "NATIVE_BASE", metas, 1, &clz)); /* Declare a "NATIVE_BASE" class which links "SCRIPT_BASE" as a meta class */
mb_make_int(cval, 123);
mb_check(mb_add_var(s, l, "C", cval, true)); /* Add a member variable "C" */
mb_check(mb_set_routine(s, l, "NATIVE_METHOD", _native_method, true)); /* Add a member method "NATIVE_METHOD" */
mb_check(mb_end_class(s, l));
return result;
}
Usage at BASIC side:
class script_base ' A BASIC class
def add(a, b)
return a + b
enddef
endclass
do_something_in_c() ' Do something in c
class foo(native_base) ' Another BASIC class links "native_base" as a meta class
endclass
print foo.add(1, 2); ' A method in meta class
print foo.c; ' A variable in native meta class
foo.native_method(456); ' A method in native meta class
- Principles
- Coding
- Data types
- Standalone shell
- Integration
- Customization
- More scripting API
- FAQ