Skip to content

Overriding operators

Wang Renxin edited this page May 31, 2022 · 3 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