Overriding operators

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

It's possible to override meta operators in MY-BASIC for a referenced usertype. Assuming got a referenced usertype defined as follow:

typedef struct _foo_t {
	int test;
} _foo_t;

And associated functions:

static void _dtor_func(struct mb_interpreter_t* s, void* f);

static void* _clone_func(struct mb_interpreter_t* s, void* f);

static int _add(struct mb_interpreter_t* s, void** l, mb_value_t* left, mb_value_t* right, mb_value_t* ret);

static int _neg(struct mb_interpreter_t* s, void** l, mb_value_t* left, mb_value_t* right, mb_value_t* ret);

static int _new_foo(struct mb_interpreter_t* s, void** l, mb_value_t* ret, int val) {
	int result = MB_FUNC_OK;
	_foo_t* f = 0;

	mb_assert(s && l && ret);

	f = (_foo_t*)malloc(sizeof(_foo_t));
	f->test = val;
	mb_make_nil(*ret);
	mb_check(mb_make_ref_value(s, f, ret, _dtor_func, _clone_func, 0, 0, 0)); /* Make a referenced usertype */
	mb_check(mb_override_value(s, l, *ret, MB_MF_ADD, _add));                 /* Override the + operator */
	mb_check(mb_override_value(s, l, *ret, MB_MF_NEG, _neg));                 /* Override the unary - operator */

	return result;
}

static void _dtor_func(struct mb_interpreter_t* s, void* f) {
	mb_assert(s && f);

	free(f);
}

static void* _clone_func(struct mb_interpreter_t* s, void* f) {
	_foo_t* ret = (_foo_t*)malloc(sizeof(_foo_t));
	_foo_t* foo = (_foo_t*)f;

	mb_assert(s && f);

	ret->test = foo->test;

	return ret;
}

Then define an add operator (+) function which accepts a _foo_t with an integer or another _foo_t, then calculates a sum:

static int _add(struct mb_interpreter_t* s, void** l, mb_value_t* left, mb_value_t* right, mb_value_t* ret) {
	int result = MB_FUNC_OK;

	mb_assert(s && l && left && right && ret);

	if(left->type == MB_DT_USERTYPE_REF && right->type == MB_DT_USERTYPE_REF) {
		_foo_t* lf = 0;
		_foo_t* rf = 0;

		mb_check(mb_get_ref_value(s, l, *left, (void**)(&lf)));
		mb_check(mb_get_ref_value(s, l, *right, (void**)(&rf)));

		mb_check(_new_foo(s, l, ret, lf->test + rf->test));
		mb_check(mb_ref_value(s, l, *ret));
	} else if(left->type == MB_DT_USERTYPE_REF && right->type == MB_DT_INT) {
		_foo_t* lf = 0;
		int_t rf = 0;

		mb_check(mb_get_ref_value(s, l, *left, (void**)(&lf)));
		rf = right->value.integer;

		mb_check(_new_foo(s, l, ret, lf->test + rf));
		mb_check(mb_ref_value(s, l, *ret));
	} else if(left->type == MB_DT_INT && right->type == MB_DT_USERTYPE_REF) {
		int_t lf = 0;
		_foo_t* rf = 0;

		lf = left->value.integer;
		mb_check(mb_get_ref_value(s, l, *right, (void**)(&rf)));

		mb_check(_new_foo(s, l, ret, lf + rf->test));
		mb_check(mb_ref_value(s, l, *ret));
	} else {
		result = MB_FUNC_ERR;
	}

	return result;
}

Another unary negative (-) operator as well:

static int _neg(struct mb_interpreter_t* s, void** l, mb_value_t* left, mb_value_t* right, mb_value_t* ret) {
	int result = MB_FUNC_OK;
	_foo_t* lf = 0;

	mb_assert(s && l && left && !right && ret);

	mb_check(mb_get_ref_value(s, l, *left, (void**)(&lf)));

	mb_check(_new_foo(s, l, ret, -lf->test));
	mb_check(mb_ref_value(s, l, *ret));

	return result;
}

We also need a BASIC function to make it possible to create a _foo_t from BASIC:

static int foo(struct mb_interpreter_t* s, void** l) {
	int result = MB_FUNC_OK;
	int_t i = 0;
	mb_value_t val;
	mb_value_t out;
	_foo_t* f = 0;

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_make_nil(val);
	mb_check(mb_pop_value(s, l, &val));
	switch(val.type) {
	case MB_DT_USERTYPE_REF:
		mb_check(mb_get_ref_value(s, l, val, (void**)(&f)));
		i = f->test;
		mb_check(mb_unref_value(s, l, val));

		break;
	case MB_DT_INT:
		i = val.value.integer;

		break;
	default:
		result = MB_FUNC_ERR;

		break;
	}

	mb_check(mb_attempt_close_bracket(s, l));

	mb_check(_new_foo(s, l, &out, i));

	mb_check(mb_push_value(s, l, out));

	return result;
}

Don't forget to register it:

mb_reg_fun(bas, foo);

After that, it's possible to apply the + operator to a _foo_t and an integer in MY-BASIC:

f = foo(100)
t = -(2 + f + 1 + f)
print t;

It's supported in MY-BASIC to override with MB_MF_IS for the IS operator, MB_MF_ADD for +, MB_MF_SUB for -, MB_MF_MUL for *, MB_MF_DIV for /, MB_MF_NEG for unary -.

Read the Overriding functions page to get information about overriding meta functions.

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.