From eede892eb07d08ee8f549417636bd3464baf013e Mon Sep 17 00:00:00 2001 From: CPunch Date: Wed, 16 Dec 2020 03:51:50 -0600 Subject: [PATCH] made OP_ITER and OP_NEXT use CObjMethods --- examples/iterator.cosmo | 9 ++++++--- src/coperators.h | 4 ++-- src/cparse.c | 2 +- src/cvm.c | 39 +++++++++++++++++++++------------------ 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/examples/iterator.cosmo b/examples/iterator.cosmo index 789c686..c5c00e8 100644 --- a/examples/iterator.cosmo +++ b/examples/iterator.cosmo @@ -17,6 +17,9 @@ proto Range end end -for i, x in Range(10) do - print("was " .. i .. ", now " .. x) -end \ No newline at end of file +local total = 0 +for i, x in Range(1000000) do + total = total + i +end + +print("total: " .. total) \ No newline at end of file diff --git a/src/coperators.h b/src/coperators.h index da40370..df7bccb 100644 --- a/src/coperators.h +++ b/src/coperators.h @@ -36,8 +36,8 @@ typedef enum { OP_SETOBJECT, OP_GETOBJECT, OP_INVOKE, - OP_ITER, // if stack[top] is an object, __iter is expected and called, else if stack[top] is a dictionary a dummy iterator object is made (SEE: cosmoV_makeIter()) - OP_NEXT, // if stack[top] is an object, __next is expected and called, expecting uint8_t return values. if stack[top] after calling is nil, jump uint16_t + OP_ITER, + OP_NEXT, // ARITHMETIC OP_ADD, diff --git a/src/cparse.c b/src/cparse.c index d2c3285..c3dd589 100644 --- a/src/cparse.c +++ b/src/cparse.c @@ -1121,7 +1121,7 @@ static void forEachLoop(CParseState *pstate) { consume(pstate, TOKEN_DO, "Expected 'do' before loop block!"); - writeu8(pstate, OP_ITER); // checks if stack[top] is iterable and makes an iterable object wrapper for CObjs like CObjDict + writeu8(pstate, OP_ITER); // checks if stack[top] is iterable and pushes the __next method onto the stack for OP_NEXT to call int loopStart = getChunk(pstate)->count; diff --git a/src/cvm.c b/src/cvm.c index add519b..fcd12bb 100644 --- a/src/cvm.c +++ b/src/cvm.c @@ -149,15 +149,15 @@ bool call(CState *state, CObjClosure *closure, int args, int nresults, int offse if (nres == -1) // panic state return false; + if (nres > nresults) // caller function wasn't expecting this many return values, cap it + nres = nresults; + // remember where the return values are CValue* results = cosmoV_getTop(state, nres-1); // pop the callframe and return results :) popCallFrame(state, offset); - if (nres > nresults) // caller function wasn't expecting this many return values, cap it - nres = nresults; - // push the return value back onto the stack memcpy(state->top, results, sizeof(CValue) * nres); // copies the return values to the top of the stack state->top += nres; // and make sure to move state->top to match @@ -580,6 +580,17 @@ int cosmoV_execute(CState *state) { cosmoV_pushValue(state, val); cosmoV_pushValue(state, cosmoV_newObj(obj)); cosmoV_call(state, 1, 1); // we expect 1 return value on the stack, the iterable object + + StkPtr iobj = cosmoV_getTop(state, 0); + + if (!IS_OBJECT(*iobj)) { + cosmoV_error(state, "Expected iterable object! '__iter' returned %s, expected object!", cosmoV_typeStr(*iobj)); + break; + } + + CObjObject *obj = (CObjObject*)cosmoV_readObj(*iobj); + + cosmoV_getObject(state, obj, cosmoV_newObj(state->iStrings[ISTRING_NEXT]), iobj); } else { cosmoV_error(state, "Expected iterable object! '__iter' not defined!"); } @@ -598,25 +609,17 @@ int cosmoV_execute(CState *state) { uint16_t jump = READUINT(); StkPtr temp = cosmoV_getTop(state, 0); // we don't actually pop this off the stack - if (!IS_OBJECT(*temp)) { - cosmoV_error(state, "Couldn't iterate over non-iterator type %s!", cosmoV_typeStr(*temp)); + if (!IS_METHOD(*temp)) { + cosmoV_error(state, "Expected '__next' to be a method, got type %s!", cosmoV_typeStr(*temp)); break; } - CObjObject *obj = (CObjObject*)cosmoV_readObj(*temp); - CValue val; + cosmoV_pushValue(state, *temp); + cosmoV_call(state, 0, nresults); - if (cosmoO_getIString(state, obj, ISTRING_NEXT, &val)) { - cosmoV_pushValue(state, val); - cosmoV_pushValue(state, *temp); - cosmoV_call(state, 1, nresults); - - if (IS_NIL(*(cosmoV_getTop(state, 0)))) { // __next returned a nil, which means to exit the loop - cosmoV_setTop(state, nresults); // pop the return values - frame->pc += jump; - } - } else { - cosmoV_error(state, "Expected iterable object! '__next' not defined!"); + if (IS_NIL(*(cosmoV_getTop(state, 0)))) { // __next returned a nil, which means to exit the loop + cosmoV_setTop(state, nresults); // pop the return values + frame->pc += jump; } break; }