made OP_ITER and OP_NEXT use CObjMethods

This commit is contained in:
CPunch 2020-12-16 03:51:50 -06:00
parent e5eca7bed6
commit eede892eb0
4 changed files with 30 additions and 24 deletions

View File

@ -17,6 +17,9 @@ proto Range
end end
end end
for i, x in Range(10) do local total = 0
print("was " .. i .. ", now " .. x) for i, x in Range(1000000) do
total = total + i
end end
print("total: " .. total)

View File

@ -36,8 +36,8 @@ typedef enum {
OP_SETOBJECT, OP_SETOBJECT,
OP_GETOBJECT, OP_GETOBJECT,
OP_INVOKE, 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_ITER,
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_NEXT,
// ARITHMETIC // ARITHMETIC
OP_ADD, OP_ADD,

View File

@ -1121,7 +1121,7 @@ static void forEachLoop(CParseState *pstate) {
consume(pstate, TOKEN_DO, "Expected 'do' before loop block!"); 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; int loopStart = getChunk(pstate)->count;

View File

@ -149,15 +149,15 @@ bool call(CState *state, CObjClosure *closure, int args, int nresults, int offse
if (nres == -1) // panic state if (nres == -1) // panic state
return false; return false;
if (nres > nresults) // caller function wasn't expecting this many return values, cap it
nres = nresults;
// remember where the return values are // remember where the return values are
CValue* results = cosmoV_getTop(state, nres-1); CValue* results = cosmoV_getTop(state, nres-1);
// pop the callframe and return results :) // pop the callframe and return results :)
popCallFrame(state, offset); 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 // 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 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 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, val);
cosmoV_pushValue(state, cosmoV_newObj(obj)); cosmoV_pushValue(state, cosmoV_newObj(obj));
cosmoV_call(state, 1, 1); // we expect 1 return value on the stack, the iterable object 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 { } else {
cosmoV_error(state, "Expected iterable object! '__iter' not defined!"); cosmoV_error(state, "Expected iterable object! '__iter' not defined!");
} }
@ -598,25 +609,17 @@ int cosmoV_execute(CState *state) {
uint16_t jump = READUINT(); uint16_t jump = READUINT();
StkPtr temp = cosmoV_getTop(state, 0); // we don't actually pop this off the stack StkPtr temp = cosmoV_getTop(state, 0); // we don't actually pop this off the stack
if (!IS_OBJECT(*temp)) { if (!IS_METHOD(*temp)) {
cosmoV_error(state, "Couldn't iterate over non-iterator type %s!", cosmoV_typeStr(*temp)); cosmoV_error(state, "Expected '__next' to be a method, got type %s!", cosmoV_typeStr(*temp));
break; break;
} }
CObjObject *obj = (CObjObject*)cosmoV_readObj(*temp); cosmoV_pushValue(state, *temp);
CValue val; cosmoV_call(state, 0, nresults);
if (cosmoO_getIString(state, obj, ISTRING_NEXT, &val)) { if (IS_NIL(*(cosmoV_getTop(state, 0)))) { // __next returned a nil, which means to exit the loop
cosmoV_pushValue(state, val); cosmoV_setTop(state, nresults); // pop the return values
cosmoV_pushValue(state, *temp); frame->pc += jump;
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!");
} }
break; break;
} }