From 0beeee0fdfb7e8f2f58d308f96d5a121d7c36090 Mon Sep 17 00:00:00 2001 From: CPunch Date: Thu, 17 Dec 2020 19:44:04 -0600 Subject: [PATCH] Added dictionary support to OP_ITER ISTRING_RESERVED was added to iStrings call & callCFunction now use memmove instead of memcpy Additionally, added cosmoO_setUserP, cosmoO_getUserP, cosmoO_setUserI and cosmoO_getUserI to the C API. --- examples/{fibtest.lua => fibtest.cosmo} | 2 +- examples/increment.cosmo | 18 ++++++- src/cobj.c | 18 +++++-- src/cobj.h | 11 ++-- src/cstate.c | 3 ++ src/cstate.h | 1 + src/cvm.c | 69 ++++++++++++++++++++++--- 7 files changed, 105 insertions(+), 17 deletions(-) rename examples/{fibtest.lua => fibtest.cosmo} (98%) diff --git a/examples/fibtest.lua b/examples/fibtest.cosmo similarity index 98% rename from examples/fibtest.lua rename to examples/fibtest.cosmo index 58fe4f8..448410b 100644 --- a/examples/fibtest.lua +++ b/examples/fibtest.cosmo @@ -8,4 +8,4 @@ end for (var i = 1; i < 40; i++) do print("The fib number of " .. i .. " is " .. fib(i)) -end +end \ No newline at end of file diff --git a/examples/increment.cosmo b/examples/increment.cosmo index 1e2f8eb..25fde17 100644 --- a/examples/increment.cosmo +++ b/examples/increment.cosmo @@ -15,6 +15,20 @@ proto Vector function __index(self, key) return self.vector[key] end + + function __iter(self) + self.iterIndex = 0 + + return self + end + + function __next(self) + if self.iterIndex > self.x then + return nil + end + + return vector[self.iterIndex++] + end end var vector = Vector() @@ -23,6 +37,6 @@ for (var i = 0; i < 100000; i++) do vector.push(i) end -for (var i = 0; i < 100000; i++) do - print(vector.pop() .. " : " .. vector[i]) +for i in vector do + print(i) end \ No newline at end of file diff --git a/src/cobj.c b/src/cobj.c index 0dfbd84..cdcffd0 100644 --- a/src/cobj.c +++ b/src/cobj.c @@ -105,7 +105,7 @@ CObjObject *cosmoO_newObject(CState *state) { CObjObject *obj = (CObjObject*)cosmoO_allocateBase(state, sizeof(CObjObject), COBJ_OBJECT); obj->proto = state->protoObj; obj->istringFlags = 0; - obj->user = NULL; // reserved for C API + obj->userP = NULL; // reserved for C API cosmoV_pushValue(state, cosmoV_newObj(obj)); // so our GC can keep track of it cosmoT_initTable(state, &obj->tbl, ARRAY_START); cosmoV_pop(state); @@ -266,12 +266,20 @@ void cosmoO_setObject(CState *state, CObjObject *object, CValue key, CValue val) } } -void cosmoO_setUserData(CState *state, CObjObject *object, void *p) { - object->user = p; +void cosmoO_setUserP(CState *state, CObjObject *object, void *p) { + object->userP = p; } -void *cosmoO_getUserData(CState *state, CObjObject *object) { - return object->user; +void *cosmoO_getUserP(CState *state, CObjObject *object) { + return object->userP; +} + +void cosmoO_setUserI(CState *state, CObjObject *object, int i) { + object->userI = i; +} + +int cosmoO_getUserI(CState *state, CObjObject *object) { + return object->userI; } bool rawgetIString(CState *state, CObjObject *object, int flag, CValue *val) { diff --git a/src/cobj.h b/src/cobj.h index 6e8017c..9bf3ef4 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -47,7 +47,10 @@ typedef struct CObjObject { CommonHeader; // "is a" CObj cosmo_Flag istringFlags; // enables us to have a much faster lookup for reserved IStrings (like __init, __index, etc.) CTable tbl; - void *user; // userdata (NULL by default) + union { // userdata (NULL by default) + void *userP; + int userI; + }; struct CObjObject *proto; // protoobject, describes the behavior of the object } CObjObject; @@ -136,8 +139,10 @@ void cosmoO_setObject(CState *state, CObjObject *object, CValue key, CValue val) bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val); bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val); -void cosmoO_setUserData(CState *state, CObjObject *object, void *p); -void *cosmoO_getUserData(CState *state, CObjObject *object); +void cosmoO_setUserP(CState *state, CObjObject *object, void *p); +void *cosmoO_getUserP(CState *state, CObjObject *object); +void cosmoO_setUserI(CState *state, CObjObject *object, int i); +int cosmoO_getUserI(CState *state, CObjObject *object); // internal string bool cosmoO_getIString(CState *state, CObjObject *object, int flag, CValue *val); diff --git a/src/cstate.c b/src/cstate.c index 0a9fd4c..2d58d9d 100644 --- a/src/cstate.c +++ b/src/cstate.c @@ -53,6 +53,9 @@ CState *cosmoV_newState() { state->iStrings[ISTRING_ITER] = cosmoO_copyString(state, "__iter", 6); state->iStrings[ISTRING_NEXT] = cosmoO_copyString(state, "__next", 6); + // for reserved members for objects + state->iStrings[ISTRING_RESERVED] = cosmoO_copyString(state, "__reserved", 10); + // set the IString flags for (int i = 0; i < ISTRING_MAX; i++) state->iStrings[i]->isIString = true; diff --git a/src/cstate.h b/src/cstate.h index 84c6e70..956a086 100644 --- a/src/cstate.h +++ b/src/cstate.h @@ -20,6 +20,7 @@ typedef enum IStringEnum { ISTRING_SETTER, // __setter ISTRING_ITER, // __iter ISTRING_NEXT, // __next + ISTRING_RESERVED, // __reserved ISTRING_MAX } IStringEnum; diff --git a/src/cvm.c b/src/cvm.c index 40fb482..bacf25f 100644 --- a/src/cvm.c +++ b/src/cvm.c @@ -126,7 +126,7 @@ static inline void callCFunction(CState *state, CosmoCFunction cfunc, int args, state->top = savedBase + offset; // set 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 + memmove(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 // now, if the caller function expected more return values, push nils onto the stack @@ -159,7 +159,7 @@ bool call(CState *state, CObjClosure *closure, int args, int nresults, int offse popCallFrame(state, offset); // 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 + memmove(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 // now, if the caller function expected more return values, push nils onto the stack @@ -285,6 +285,7 @@ COSMO_API void cosmoV_makeDictionary(CState *state, int pairs) { } COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, CValue *val) { + cosmoV_pushValue(state, cosmoV_newObj(object)); if (cosmoO_getObject(state, object, key, val)) { if (IS_OBJ(*val)) { if (cosmoV_readObj(*val)->type == COBJ_CLOSURE) { // is it a function? if so, make it a method to the current object @@ -296,12 +297,53 @@ COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, C } } + cosmoV_pop(state); return true; } + cosmoV_pop(state); return false; } +int _dict__next(CState *state, int nargs, CValue *args) { + if (nargs != 1) { + cosmoV_error(state, "Expected 1 parameter, %d received!", nargs); + return 0; + } + + if (!IS_OBJECT(args[0])) { + cosmoV_error(state, "Expected iterable object, %s received!", cosmoV_typeStr(args[0])); + return 0; + } + + CObjObject *obj = cosmoV_readObject(args[0]); + int index = cosmoO_getUserI(state, obj); // we store the index in the userdata + CValue val; + + cosmoO_getIString(state, obj, ISTRING_RESERVED, &val); + + if (!IS_DICT(val)) { + return 0; // someone set the __reserved member to something else. this will exit the iterator loop + } + + CObjDict *dict = (CObjDict*)cosmoV_readObj(val); + + // while the entry is invalid, go to the next entry + CTableEntry *entry; + do { + entry = &dict->tbl.table[index++]; + } while (IS_NIL(entry->key) && index < dict->tbl.capacity); + cosmoO_setUserI(state, obj, index); // update the userdata + + if (!IS_NIL(entry->key)) { // if the entry is valid, return it's key and value pair + cosmoV_pushValue(state, entry->key); + cosmoV_pushValue(state, entry->val); + return 2; // we pushed 2 values onto the stack for the return values + } else { + return 0; // we have nothing to return, this should exit the iterator loop + } +} + #define NUMBEROP(typeConst, op) \ StkPtr valA = cosmoV_getTop(state, 1); \ StkPtr valB = cosmoV_getTop(state, 0); \ @@ -564,14 +606,29 @@ int cosmoV_execute(CState *state) { switch (cosmoV_readObj(*temp)->type) { case COBJ_DICT: { - //CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp); + CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp); - // TODO: add cosmoV_makeIter, which will make a dummy iterable object for dictionaries - cosmoV_error(state, "unimpl. mass ping cpunch!!!!"); + cosmoV_pushValue(state, cosmoV_newObj(state->iStrings[ISTRING_RESERVED])); // key + cosmoV_pushValue(state, cosmoV_newObj(dict)); // value + + cosmoV_pushLString(state, "__next", 6); // key + CObjCFunction *dict_next = cosmoO_newCFunction(state, _dict__next); + cosmoV_pushValue(state, cosmoV_newObj(dict_next)); // value + + cosmoV_makeObject(state, 2); // pushes the new object to the stack + + CObjObject *obj = cosmoV_readObject(*(cosmoV_getTop(state, 0))); + cosmoO_setUserI(state, obj, 0); // increment for iterator + + // make our CObjMethod for OP_NEXT to call + CObjMethod *method = cosmoO_newCMethod(state, dict_next, obj); + + cosmoV_setTop(state, 2); // pops the object & the dict + cosmoV_pushValue(state, cosmoV_newObj(method)); // pushes the method for OP_NEXT break; } case COBJ_OBJECT: { - CObjObject *obj = (CObjObject*)cosmoV_readObj(*temp); + CObjObject *obj = cosmoV_readObject(*temp); CValue val; // grab __iter & call it