Callback

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

Call from BASIC to BASIC

The CALL statement is used to get a invokable routine value as:

def fun(msg)
	print msg;
enddef

routine = call(fun) ' Get a routine value
routine("hello")    ' Invoke a routine value

Be aware it requires a pair of brackets comes along with a CALL statement to get a invokable value, otherwise it calls the routine instantly.

This mechanism is useful when you are tending to store a sub routine value for later invoking.

Call from C to BASIC

Besides, it's possible to call a BASIC routine from C side as well, for instance, assuming we got a routine defined in BASIC:

def fun(num)
	print num;

	return num * 2 ' Return a new value back
enddef

native ' This is a registered native function

Note it won't work if call NATIVE before the DEF fun statement, because the interpreter doesn't know necessary information until a DEF statement is evaluated during runtime.

Now it's possible to callback fun at C side as follow:

static int _native(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;

	mb_assert(s && l);

	mb_check(mb_attempt_func_begin(s, l));
	mb_check(mb_attempt_func_end(s, l));

	{
		mb_value_t routine;
		mb_value_t args[1];
		mb_value_t ret;

		mb_get_routine(s, l, "FUN", &routine);   /* Get the "FUN" routine */

		args[0].type = MB_DT_INT;
		args[0].value.integer = 123;
		mb_make_nil(ret);
		mb_eval_routine(s, l, routine, args, 1, &ret); /* Evaluate the "FUN" routine with arguments, and get the returned value */
		printf("Returned %d.\n", ret.value.integer);
	}

	return result;
}

Note it needs uppercase identifier to lookup a routine (and other symbols in MY-BASIC). You always have to pass an mb_value_t args[1] array to mb_eval_routine(s, l, routine, args, 0, 0);, even if it's a parameterless routine. The last parameter mb_value_t* ret is optional.

Call from BASIC to C

There is no difference from a routine defined in BASIC and in C. Assuming we have two C functions as follow:

static int _foo(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;
}

static int _test(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;

	mb_assert(s && l);

	mb_check(mb_attempt_func_begin(s, l));
	mb_check(mb_attempt_func_end(s, l));

	mb_set_routine(s, l, "FOO", _foo, true); /* Define a routine named "FOO" */

	return result;
}

Don't forget to register it:

mb_reg_fun(bas, _test);

Now we can call the C function _foo as a routine:

test     ' Call "test"

foo(123) ' "foo" is defined as a routine after calling "test"
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.