Skip to content

Using iterators

Wang Renxin edited this page May 31, 2022 · 3 revisions

An iterator is an object that enables a programmer to traverse some data types in MY-BASIC. You may implement generator or just traverse all values with it.

Use the ITERATOR statement to get an iterator value; then use MOVE_NEXT to check whether an iteration finishes; you may use GET, and VAL to get details of current step.

It also offers ability to traverse all elements with a FOR statement.

Collections

List

Iterate a list with an explicit pattern:

l = list(1, 1, 2, 3, 5, 8)
i = iterator(l)
while move_next(i)
	print get(i);
wend

An increasing by 1 ranged iteration, with a FOR loop:

for i in list(1 to 5)
	print i;
next

A decreasing by 1 ranged iteration, with a FOR loop:

for i in list(5 to 1)
	print i;
next

Dictionary

Use the GET statement to get the key of a dictionary iterator, and VAL to get the value:

d = dict("one", 1, "two", 2, "three", 3)
i = iterator(d)
while move_next(i)
	print get(i), ", ", val(i);
wend

Iterate previous dictionary d with a FOR loop, while the iteration variable represents the key:

for i in d
	print i, ", ", d(i);
next

Class

It's possible to make an iterable class instance with overridden functions. It requires overriding for ITERATOR, MOVE_NEXT and GET.

Create class instances:

class clz
	var n = 0

	def _iterator()
		return me ' Return self for example
	enddef
	def _move_next()
		n = n + 1

		return n < 5
	enddef
	def _get()
		return n
	enddef
endclass

k = new(clz)
z = new(clz)

Iterate with an explicit pattern:

i = iterator(k)
while move_next(i)
	print get(i);
wend

Iterate with a FOR loop:

for i in z
	print i;
next

Referenced usertype

It's possible to make an iterable referenced usertype with overridden functions. It requires ITERATOR, MOVE_NEXT and GET.

Note that an iterator of a referenced usertype is also a referenced usertype, and in this sample, it's the value itself.

The implementation in C:

typedef struct Fibonacci {
	int i;
	int_t m;
	int_t n;
} Fibonacci;

static void _unref(struct mb_interpreter_t* s, void* d) {
	Fibonacci* p = (Fibonacci*)d;

	mb_assert(s);

	free(p);
}

static void* _clone(struct mb_interpreter_t* s, void* d) {
	Fibonacci* p = (Fibonacci*)d;
	Fibonacci* q = (Fibonacci*)malloc(sizeof(Fibonacci));

	mb_assert(s);

	*q = *p;

	return q;
}

static mb_meta_status_e _fib_coll(struct mb_interpreter_t* s, void** l, mb_value_t* z, const char* n) {
	Fibonacci* fib = 0;

	mb_assert(s && l);

	mb_get_ref_value(s, l, *z, (void**)&fib);

	if(!strcmp(n, "ITERATOR")) {
		mb_push_value(s, l, *z);

		return (mb_meta_status_e)(MB_MS_DONE | MB_MS_RETURNED);
	} else if(!strcmp(n, "MOVE_NEXT")) {
		mb_push_int(s, l, fib->i++ < 6 ? true : false);

		return (mb_meta_status_e)(MB_MS_DONE | MB_MS_RETURNED);
	}

	return MB_MS_NONE;
}

static mb_meta_status_e _fib_func(struct mb_interpreter_t* s, void** l, mb_value_t* z, const char* n) {
	Fibonacci* fib = 0;

	mb_assert(s && l);

	mb_get_ref_value(s, l, *z, (void**)&fib);

	if(!strcmp(n, "GET")) {
		if(fib->i < 3) {
			mb_push_int(s, l, 1);
		} else {
			int_t r = fib->n + fib->m;
			fib->m = fib->n;
			fib->n = r;
			mb_push_int(s, l, r);
		}

		return (mb_meta_status_e)(MB_MS_DONE | MB_MS_RETURNED);
	}

	return MB_MS_NONE;
}

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

	mb_assert(s && l);

	mb_check(mb_attempt_open_bracket(s, l));

	mb_check(mb_attempt_close_bracket(s, l));

	{
		mb_value_t ret;
		Fibonacci* p = (Fibonacci*)malloc(sizeof(Fibonacci));
		p->i = 0;
		p->m = 1;
		p->n = 1;
		mb_make_ref_value(s, p, &ret, _unref, _clone, 0, 0, 0);
		mb_override_value(s, l, ret, MB_MF_COLL, _fib_coll);
		mb_override_value(s, l, ret, MB_MF_FUNC, _fib_func);
		mb_check(mb_push_value(s, l, ret));
	}

	return result;
}

Don't forget to register it with:

mb_register_func(bas, "FIBONACCI", _fibonacci);

Iterate with an explicit pattern:

f = fibonacci()
i = iterator(f)
while move_next(i)
	print get(i);
wend

Iterate with a FOR loop:

f = fibonacci()
for i in f
	print i;
next
Clone this wiki locally