Defining a class in C

Wang Renxin edited this page Nov 19, 2017 · 2 revisions

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));

	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_check(mb_get_value_by_name(s, l, "SCRIPT_BASE", &script_base));     /* Get the "SCRIPT_BASE" class from BASIC */
	metas[0] = &script_base;

	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

do_something_in_c()     ' Do something in c

class foo(native_base)  ' Another BASIC class links "native_base" as a meta class

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
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.