diff --git a/src/cbaselib.c b/src/cbaselib.c index 49d684b..b94d64d 100644 --- a/src/cbaselib.c +++ b/src/cbaselib.c @@ -131,13 +131,24 @@ void cosmoB_loadLibrary(CState *state) { // register these all to the global table cosmoV_register(state, 5); + + // make string object for CObjStrings + + // sub + cosmoV_pushString(state, "sub"); + cosmoV_pushCFunction(state, cosmoB_sSub); + + cosmoV_makeObject(state, 1); + + StkPtr obj = cosmoV_pop(state); + state->protoObjects[COBJ_STRING] = cosmoV_readObject(*obj); } // ================================================================ [DEBUG] ================================================================ int cosmoB_dsetProto(CState *state, int nargs, CValue *args) { if (nargs == 2) { - CObjObject *obj = cosmoV_readObject(args[0]); // object to set proto too + CObj *obj = cosmoV_readObj(args[0]); // object to set proto too CObjObject *proto = cosmoV_readObject(args[1]); obj->proto = proto; // boom done @@ -153,7 +164,7 @@ int cosmoB_dgetProto(CState *state, int nargs, CValue *args) { cosmoV_error(state, "Expected 1 argument, got %d!", nargs); } - cosmoV_pushValue(state, cosmoV_newObj(cosmoV_readObject(args[0])->proto)); // just return the proto + cosmoV_pushValue(state, cosmoV_newObj(cosmoV_readObject(args[0])->_obj.proto)); // just return the proto return 1; // 1 result } @@ -179,6 +190,6 @@ void cosmoB_loadDebug(CState *state) { // we call makeObject leting it know there are 2 sets of key & value pairs on the stack cosmoV_makeObject(state, 2); - // set debug proto to the debug object - state->protoObj = cosmoV_readObject(*cosmoV_pop(state)); + // set debug protos to the debug object + state->protoObjects[COBJ_OBJECT] = cosmoV_readObject(*cosmoV_pop(state)); } diff --git a/src/cmem.c b/src/cmem.c index 92df1ba..0ca5ce8 100644 --- a/src/cmem.c +++ b/src/cmem.c @@ -85,6 +85,7 @@ void markArray(CState *state, CValueArray *array) { // mark all references associated with the object void blackenObject(CState *state, CObj *obj) { + markObject(state, (CObj*)obj->proto); switch (obj->type) { case COBJ_STRING: case COBJ_CFUNCTION: @@ -94,7 +95,6 @@ void blackenObject(CState *state, CObj *obj) { // mark everything this object is keeping track of CObjObject *cobj = (CObjObject*)obj; markTable(state, &cobj->tbl); - markObject(state, (CObj*)cobj->proto); break; } case COBJ_DICT: { // dictionaries are just wrappers for CTable @@ -243,9 +243,11 @@ void markRoots(CState *state) { markUserRoots(state); // mark other misc. internally reserved objects - markObject(state, (CObj*)state->protoObj); markObject(state, (CObj*)state->error); + for (int i = 0; i < COBJ_MAX; i++) + markObject(state, (CObj*)state->protoObjects[i]); + traceGrays(state); } diff --git a/src/cobj.c b/src/cobj.c index 9f6dcc3..17d5d54 100644 --- a/src/cobj.c +++ b/src/cobj.c @@ -22,6 +22,7 @@ CObj *cosmoO_allocateBase(CState *state, size_t sz, CObjType type) { CObj* obj = (CObj*)cosmoM_xmalloc(state, sz); obj->type = type; obj->isMarked = false; + obj->proto = state->protoObjects[type]; obj->next = state->objects; state->objects = obj; @@ -88,6 +89,7 @@ void cosmoO_free(CState *state, CObj* obj) { cosmoM_free(state, CObjClosure, closure); break; } + case COBJ_MAX: { /* stubbed, should never happen */ } } } @@ -110,7 +112,6 @@ bool cosmoO_equal(CObj* obj1, CObj* obj2) { CObjObject *cosmoO_newObject(CState *state) { CObjObject *obj = (CObjObject*)cosmoO_allocateBase(state, sizeof(CObjObject), COBJ_OBJECT); - obj->proto = state->protoObj; obj->istringFlags = 0; obj->userP = NULL; // reserved for C API cosmoV_pushValue(state, cosmoV_newObj(obj)); // so our GC can keep track of it @@ -164,16 +165,9 @@ CObjError *cosmoO_newError(CState *state, CValue err) { return cerror; } -CObjMethod *cosmoO_newCMethod(CState *state, CObjCFunction *func, CObjObject *obj) { +CObjMethod *cosmoO_newMethod(CState *state, CValue func, CObj *obj) { CObjMethod *method = (CObjMethod*)cosmoO_allocateBase(state, sizeof(CObjMethod), COBJ_METHOD); - method->func = cosmoV_newObj(func); - method->obj = obj; - return method; -} - -CObjMethod *cosmoO_newMethod(CState *state, CObjClosure *func, CObjObject *obj) { - CObjMethod *method = (CObjMethod*)cosmoO_allocateBase(state, sizeof(CObjMethod), COBJ_METHOD); - method->func = cosmoV_newObj(func); + method->func = func; method->obj = obj; return method; } @@ -304,8 +298,10 @@ bool cosmoO_getRawObject(CState *state, CObjObject *object, CValue key, CValue * return true; } - if (object->proto != NULL && cosmoO_getRawObject(state, object->proto, key, val)) + if (object->_obj.proto != NULL && cosmoO_getRawObject(state, object->_obj.proto, key, val)) return true; + + *val = cosmoV_newNil(); return false; // no protoobject to check against / key not found } @@ -325,7 +321,7 @@ void cosmoO_setRawObject(CState *state, CObjObject *object, CValue key, CValue v } // if the key is an IString, we need to reset the cache - if (IS_STRING(key) && ((CObjString*)cosmoV_readObj(key))->isIString) + if (IS_STRING(key) && cosmoV_readString(key)->isIString) object->istringFlags = 0; // reset cache if (IS_NIL(val)) { // if we're setting an index to nil, we can safely mark that as a tombstone @@ -371,7 +367,7 @@ bool cosmoO_getIString(CState *state, CObjObject *object, int flag, CValue *val) do { if (rawgetIString(state, obj, flag, val)) return true; - } while ((obj = obj->proto) != NULL); // sets obj to it's proto and compares it to NULL + } while ((obj = obj->_obj.proto) != NULL); // sets obj to it's proto and compares it to NULL return false; // obj->proto was false, the istring doesn't exist in this object chain } @@ -409,7 +405,29 @@ bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue } CObjString *cosmoO_toString(CState *state, CObj *obj) { - switch (obj->type) { + CObjObject *protoObject = cosmoO_grabProto(obj); + CValue res; + + // use user-defined __tostring + if (protoObject != NULL && cosmoO_getIString(state, protoObject, ISTRING_TOSTRING, &res)) { + cosmoV_pushValue(state, res); + cosmoV_pushValue(state, cosmoV_newObj(obj)); + if (cosmoV_call(state, 1, 1) != COSMOVM_OK) + return cosmoO_copyString(state, "", 5); + + // make sure the __tostring function returned a string + StkPtr ret = cosmoV_getTop(state, 0); + if (!IS_STRING(*ret)) { + cosmoV_error(state, "__tostring expected to return , got %s!", cosmoV_typeStr(*ret)); + return cosmoO_copyString(state, "", 5); + } + + // return string + cosmoV_pop(state); + return (CObjString*)cosmoV_readObj(*ret); + } + + switch (obj->type) { case COBJ_STRING: { return (CObjString*)obj; } @@ -422,30 +440,9 @@ CObjString *cosmoO_toString(CState *state, CObj *obj) { return func->name != NULL ? func->name : cosmoO_copyString(state, UNNAMEDCHUNK, strlen(UNNAMEDCHUNK)); } case COBJ_OBJECT: { - CObjObject *object = (CObjObject*)obj; - CValue res; - - if (cosmoO_getIString(state, object, ISTRING_TOSTRING, &res)) { - cosmoV_pushValue(state, res); - cosmoV_pushValue(state, cosmoV_newObj(object)); - if (cosmoV_call(state, 1, 1) != COSMOVM_OK) - return cosmoO_copyString(state, "", 5); - - // make sure the __tostring function returned a string - StkPtr ret = cosmoV_getTop(state, 0); - if (!IS_STRING(*ret)) { - cosmoV_error(state, "__tostring expected to return , got %s!", cosmoV_typeStr(*ret)); - return cosmoO_copyString(state, "", 5); - } - - // return string - cosmoV_pop(state); - return (CObjString*)cosmoV_readObj(*ret); - } else { - char buf[64]; - int sz = sprintf(buf, " %p", (void*)obj) + 1; // +1 for the null character - return cosmoO_copyString(state, buf, sz); - } + char buf[64]; + int sz = sprintf(buf, " %p", (void*)obj) + 1; // +1 for the null character + return cosmoO_copyString(state, buf, sz); } case COBJ_ERROR: { CObjError *err = (CObjError*)obj; diff --git a/src/cobj.h b/src/cobj.h index 3348f32..b029a40 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -2,14 +2,6 @@ #define COBJ_H #include "cosmo.h" -#include "cstate.h" -#include "cchunk.h" -#include "cvalue.h" -#include "ctable.h" - -typedef struct CState CState; -typedef struct CCallFrame CCallFrame; -typedef uint32_t cosmo_Flag; typedef enum { COBJ_STRING, @@ -22,8 +14,18 @@ typedef enum { COBJ_METHOD, COBJ_CLOSURE, COBJ_UPVALUE, + COBJ_MAX } CObjType; +#include "cstate.h" +#include "cchunk.h" +#include "cvalue.h" +#include "ctable.h" + +typedef struct CState CState; +typedef struct CCallFrame CCallFrame; +typedef uint32_t cosmo_Flag; + #define CommonHeader CObj _obj #define readFlag(x, flag) (x & (1u << flag)) #define setFlagOn(x, flag) (x |= (1u << flag)) @@ -35,6 +37,7 @@ typedef struct CObj { bool isMarked; // for the GC struct CObj *next; struct CObj *nextRoot; // for the root linked list + struct CObjObject *proto; // protoobject, describes the behavior of the object } CObj; typedef struct CObjString { @@ -62,7 +65,6 @@ typedef struct CObjObject { void *userP; int userI; }; - struct CObjObject *proto; // protoobject, describes the behavior of the object } CObjObject; typedef struct CObjDict { // dictionary, a wrapper for CTable @@ -94,7 +96,7 @@ typedef struct CObjClosure { typedef struct CObjMethod { CommonHeader; // "is a " CObj - CObjObject *obj; // obj this method is bound too + CObj *obj; // obj this method is bound too CValue func; } CObjMethod; @@ -141,12 +143,21 @@ CObjDict *cosmoO_newDictionary(CState *state); CObjFunction *cosmoO_newFunction(CState *state); CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func); CObjError *cosmoO_newError(CState *state, CValue err); -CObjMethod *cosmoO_newMethod(CState *state, CObjClosure *func, CObjObject *obj); -CObjMethod *cosmoO_newCMethod(CState *state, CObjCFunction *func, CObjObject *obj); +CObjMethod *cosmoO_newMethod(CState *state, CValue func, CObj *obj); CObjClosure *cosmoO_newClosure(CState *state, CObjFunction *func); CObjString *cosmoO_toString(CState *state, CObj *val); CObjUpval *cosmoO_newUpvalue(CState *state, CValue *val); +// grabs the base proto of the CObj* (if CObj is a CObjObject, that is returned) +static inline CObjObject *cosmoO_grabProto(CObj *obj) { + CObjObject *object = obj->proto; + + if (obj->type == COBJ_OBJECT) + object = (CObjObject*)obj; + + return object; +} + bool cosmoO_getRawObject(CState *state, CObjObject *object, CValue key, CValue *val); void cosmoO_setRawObject(CState *state, CObjObject *object, CValue key, CValue val); bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val); diff --git a/src/cparse.c b/src/cparse.c index 1298c4d..7ea7223 100644 --- a/src/cparse.c +++ b/src/cparse.c @@ -1357,7 +1357,7 @@ static void forLoop(CParseState *pstate) { startLoop(pstate); int iteratorStart = getChunk(pstate)->count; - expression(pstate, 0, true); + expressionPrecedence(pstate, 0, PREC_ASSIGNMENT, true); // any expression (including assignment) consume(pstate, TOKEN_RIGHT_PAREN, "Expected ')' after iterator"); writeJmpBack(pstate, loopStart); diff --git a/src/cstate.c b/src/cstate.c index 8be1f51..4824218 100644 --- a/src/cstate.c +++ b/src/cstate.c @@ -32,7 +32,6 @@ CState *cosmoV_newState() { state->frameCount = 0; state->openUpvalues = NULL; - state->protoObj = NULL; state->error = NULL; cosmoT_initTable(state, &state->strings, 8); // init string table @@ -62,6 +61,10 @@ CState *cosmoV_newState() { // set the IString flags for (int i = 0; i < ISTRING_MAX; i++) state->iStrings[i]->isIString = true; + + // set default proto objects + for (int i = 0; i < COBJ_MAX; i++) + state->protoObjects[i] = NULL; return state; } diff --git a/src/cstate.h b/src/cstate.h index 1791734..c24fc95 100644 --- a/src/cstate.h +++ b/src/cstate.h @@ -2,8 +2,8 @@ #define CSTATE_H #include "cosmo.h" -#include "cvalue.h" #include "cobj.h" +#include "cvalue.h" #include "ctable.h" typedef struct CCallFrame { @@ -36,7 +36,6 @@ typedef struct CState { int freezeGC; // when > 0, GC events will be ignored (for internal use) int frameCount; - CObjObject *protoObj; // start met obj for all objects (NULL by default) CObjError *error; // NULL, unless panic is true CObj *objects; // tracks all of our allocated objects CObj *userRoots; // user definable roots, this holds CObjs that should be considered "roots", lets the VM know you are holding a reference to a CObj in your code @@ -49,6 +48,7 @@ typedef struct CState { CTable globals; CValue *top; // top of the stack + CObjObject *protoObjects[COBJ_MAX]; // proto object for each COBJ type [NULL = no default proto] CObjString *iStrings[ISTRING_MAX]; // strings used internally by the VM, eg. __init, __index & friends CCallFrame callFrame[FRAME_MAX]; // call frames CValue stack[STACK_MAX]; // stack diff --git a/src/cvm.c b/src/cvm.c index c1cc6c2..271bbee 100644 --- a/src/cvm.c +++ b/src/cvm.c @@ -173,7 +173,7 @@ void cosmoV_concat(CState *state, int vals) { } int cosmoV_execute(CState *state); -bool invokeMethod(CState* state, CObjObject *obj, CValue func, int args, int nresults, int offset); +bool invokeMethod(CState* state, CObj *obj, CValue func, int args, int nresults, int offset); /* calls a native C Function with # args on the stack, nresults are pushed onto the stack upon return. @@ -293,12 +293,12 @@ bool callCValue(CState *state, CValue func, int args, int nresults, int offset) case COBJ_OBJECT: { // object is being instantiated, making another object CObjObject *protoObj = (CObjObject*)cosmoV_readObj(func); CObjObject *newObj = cosmoO_newObject(state); - newObj->proto = protoObj; + newObj->_obj.proto = protoObj; CValue ret; // check if they defined an initializer (we accept 0 return values) if (cosmoO_getIString(state, protoObj, ISTRING_INIT, &ret)) { - if (!invokeMethod(state, newObj, ret, args, 0, offset + 1)) + if (!invokeMethod(state, (CObj*)newObj, ret, args, 0, offset + 1)) return false; } else { // no default initializer @@ -324,7 +324,7 @@ bool callCValue(CState *state, CValue func, int args, int nresults, int offset) return true; } -bool invokeMethod(CState* state, CObjObject *obj, CValue func, int args, int nresults, int offset) { +bool invokeMethod(CState* state, CObj *obj, CValue func, int args, int nresults, int offset) { // first, set the first argument to the object StkPtr temp = cosmoV_getTop(state, args); *temp = cosmoV_newObj(obj); @@ -409,25 +409,44 @@ COSMO_API void cosmoV_makeDictionary(CState *state, int pairs) { cosmoV_pushValue(state, cosmoV_newObj(newObj)); } -COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, CValue *val) { +COSMO_API bool cosmoV_get(CState *state, CObj *_obj, CValue key, CValue *val) { + CObjObject *object = cosmoO_grabProto(_obj); + + // no proto to get from + if (object == NULL) { + cosmoV_error(state, "No proto defined! Couldn't get from type %s", cosmoO_typeStr(_obj)); + *val = cosmoV_newNil(); + return false; + } + cosmoV_pushValue(state, cosmoV_newObj(object)); + if (cosmoO_getRawObject(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 - CObjMethod *method = cosmoO_newMethod(state, (CObjClosure*)cosmoV_readObj(*val), object); - *val = cosmoV_newObj(method); - } else if (cosmoV_readObj(*val)->type == COBJ_CFUNCTION) { - CObjMethod *method = cosmoO_newCMethod(state, (CObjCFunction*)cosmoV_readObj(*val), object); - *val = cosmoV_newObj(method); - } // else, just pass the raw object - } + // is it a function? if so, make it a method to the current object + if (IS_OBJ(*val) && (cosmoV_readObj(*val)->type == COBJ_CLOSURE || cosmoV_readObj(*val)->type == COBJ_CFUNCTION)) { + CObjMethod *method = cosmoO_newMethod(state, *val, _obj); + *val = cosmoV_newObj(method); + } // else, just pass the raw object cosmoV_pop(state); return true; } cosmoV_pop(state); - return false; + return true; +} + +COSMO_API bool cosmoV_set(CState *state, CObj *_obj, CValue key, CValue val) { + CObjObject *object = cosmoO_grabProto(_obj); + + // no proto to set to + if (object == NULL) { + cosmoV_error(state, "No proto defined! Couldn't set to type %s", cosmoO_typeStr(_obj)); + return false; + } + + cosmoO_setRawObject(state, object, key, val); + return true; } int _dict__next(CState *state, int nargs, CValue *args) { @@ -615,17 +634,19 @@ int cosmoV_execute(CState *state) { cosmoT_get(&dict->tbl, *key, &val); break; } - case COBJ_OBJECT: { // check for __index - CObjObject *object = (CObjObject*)cosmoV_readObj(*temp); + default: { // check for __index metamethod + CObjObject *object = cosmoO_grabProto(cosmoV_readObj(*temp)); + + if (object == NULL) { + cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp)); + return -1; + } if (!cosmoO_indexObject(state, object, *key, &val)) // if returns false, cosmoV_error was called return -1; break; } - default: - cosmoV_error(state, "Couldn't index type %s!", cosmoV_typeStr(*temp)); - return -1; } cosmoV_setTop(state, 2); // pops the object & the key @@ -651,17 +672,19 @@ int cosmoV_execute(CState *state) { *newVal = *value; // set the index break; } - case COBJ_OBJECT: { // check for __newindex - CObjObject *object = (CObjObject*)cosmoV_readObj(*temp); + default: { // check for __newindex + CObjObject *object = cosmoO_grabProto(cosmoV_readObj(*temp)); + + if (object == NULL) { + cosmoV_error(state, "No proto defined! Couldn't __newindex from type %s", cosmoV_typeStr(*temp)); + return -1; + } if (!cosmoO_newIndexObject(state, object, *key, *value)) // if it returns false, cosmoV_error was called return -1; break; } - default: - cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp)); - return -1; } // pop everything off the stack @@ -692,15 +715,9 @@ int cosmoV_execute(CState *state) { cosmoT_get(&dict->tbl, constants[ident], &val); break; } - case COBJ_OBJECT: { - CObjObject *object = (CObjObject*)cosmoV_readObj(*temp); - - cosmoV_getObject(state, object, constants[ident], &val); - break; - } default: - cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp)); - return -1; + if (!cosmoV_get(state, cosmoV_readObj(*temp), constants[ident], &val)) + return -1; } } else { cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp)); @@ -726,15 +743,9 @@ int cosmoV_execute(CState *state) { *newVal = *value; // set the index break; } - case COBJ_OBJECT: { - CObjObject *object = (CObjObject*)cosmoV_readObj(*temp); - - cosmoO_setRawObject(state, object, constants[ident], *value); - break; - } default: - cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp)); - return -1; + if (!cosmoV_set(state, cosmoV_readObj(*temp), constants[ident], *value)) + return -1; } } else { cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp)); @@ -765,18 +776,20 @@ int cosmoV_execute(CState *state) { return -1; break; } - case COBJ_OBJECT: { - CObjObject *object = (CObjObject*)cosmoV_readObj(*temp); + default: { + CObjObject *object = cosmoO_grabProto(cosmoV_readObj(*temp)); - cosmoO_getRawObject(state, object, *key, &val); // we use cosmoO_getRawObject instead of the cosmoV_getObject wrapper so we get the raw value from the object instead of the CObjMethod wrapper + if (object == NULL) { + cosmoV_error(state, "No proto defined! Couldn't get from type %s!", cosmoV_typeStr(*temp)); + return -1; + } + + cosmoO_getRawObject(state, object, *key, &val); // we use cosmoO_getRawObject instead of the wrapper so we get the raw value from the object instead of the CObjMethod wrapper // now invoke the method! - invokeMethod(state, object, val, args, nres, 0); + invokeMethod(state, cosmoV_readObj(*temp), val, args, nres, 0); break; } - default: - cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp)); - return -1; } } else { cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp)); @@ -793,9 +806,10 @@ int cosmoV_execute(CState *state) { return -1; } - switch (cosmoV_readObj(*temp)->type) { + CObj *obj = cosmoV_readObj(*temp); + switch (obj->type) { case COBJ_DICT: { - CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp); + CObjDict *dict = (CObjDict*)obj; cosmoV_pushValue(state, cosmoV_newObj(state->iStrings[ISTRING_RESERVED])); // key cosmoV_pushValue(state, cosmoV_newObj(dict)); // value @@ -810,18 +824,23 @@ int cosmoV_execute(CState *state) { cosmoO_setUserI(state, obj, 0); // increment for iterator // make our CObjMethod for OP_NEXT to call - CObjMethod *method = cosmoO_newCMethod(state, dict_next, obj); + CObjMethod *method = cosmoO_newMethod(state, cosmoV_newObj(dict_next), (CObj*)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 = cosmoV_readObject(*temp); + default: { + CObjObject *object = cosmoO_grabProto(obj); CValue val; + if (object == NULL) { + cosmoV_error(state, "No proto defined! Couldn't get from type %s", cosmoO_typeStr(obj)); + return -1; + } + // grab __iter & call it - if (cosmoO_getIString(state, obj, ISTRING_ITER, &val)) { + if (cosmoO_getIString(state, object, ISTRING_ITER, &val)) { cosmoV_pop(state); // pop the object from the stack cosmoV_pushValue(state, val); cosmoV_pushValue(state, cosmoV_newObj(obj)); @@ -831,13 +850,12 @@ int cosmoV_execute(CState *state) { StkPtr iObj = cosmoV_getTop(state, 0); if (!IS_OBJECT(*iObj)) { - cosmoV_error(state, "Expected iterable object! '__iter' returned %s, expected object!", cosmoV_typeStr(*iObj)); + cosmoV_error(state, "Expected iterable object! '__iter' returned %s, expected !", cosmoV_typeStr(*iObj)); return -1; } - CObjObject *obj = (CObjObject*)cosmoV_readObj(*iObj); - - cosmoV_getObject(state, obj, cosmoV_newObj(state->iStrings[ISTRING_NEXT]), iObj); + // get __next method and place it at the top of the stack + cosmoV_get(state, cosmoV_readObj(*iObj), cosmoV_newObj(state->iStrings[ISTRING_NEXT]), iObj); } else { cosmoV_error(state, "Expected iterable object! '__iter' not defined!"); return -1; @@ -845,9 +863,6 @@ int cosmoV_execute(CState *state) { break; } - default: - cosmoV_error(state, "Couldn't iterate over non-iterator type %s!", cosmoV_typeStr(*temp)); - return -1; } break; } @@ -1005,9 +1020,14 @@ int cosmoV_execute(CState *state) { } break; } - case COBJ_OBJECT: { - CObjObject *object = (CObjObject*)cosmoV_readObj(*temp); + default: { + CObjObject *object = cosmoO_grabProto(cosmoV_readObj(*temp)); CValue val; + + if (object == NULL) { + cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp)); + return -1; + } // call __index if (cosmoO_indexObject(state, object, *key, &val)) { @@ -1015,17 +1035,17 @@ int cosmoV_execute(CState *state) { cosmoV_pushValue(state, val); // pushes old value onto the stack :) // call __newindex - cosmoO_newIndexObject(state, object, *key, cosmoV_newNumber(cosmoV_readNumber(val) + inc)); + if (!cosmoO_newIndexObject(state, object, *key, cosmoV_newNumber(cosmoV_readNumber(val) + inc))) + return -1; } else { cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val)); return -1; } + } else { + return -1; } break; } - default: - cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp)); - return -1; } } else { cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp)); @@ -1043,25 +1063,6 @@ int cosmoV_execute(CState *state) { // sanity check if (IS_OBJ(*temp)) { switch (cosmoV_readObj(*temp)->type) { - case COBJ_OBJECT: { - CObjObject *object = (CObjObject*)cosmoV_readObj(*temp); - CValue val; - - cosmoO_getRawObject(state, object, ident, &val); - - // pop the object off the stack - cosmoV_pop(state); - - // check that it's a number value - if (IS_NUMBER(val)) { - cosmoV_pushValue(state, val); // pushes old value onto the stack :) - cosmoO_setRawObject(state, object, ident, cosmoV_newNumber(cosmoV_readNumber(val) + inc)); - } else { - cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val)); - return -1; - } - break; - } case COBJ_DICT: { CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp); CValue *val = cosmoT_insert(state, &dict->tbl, ident); @@ -1078,9 +1079,27 @@ int cosmoV_execute(CState *state) { } break; } - default: - cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp)); - return -1; + default: { + CObj *obj = cosmoV_readObj(*temp); + CValue val; + + if (!cosmoV_get(state, obj, ident, &val)) + return -1; + + // pop the object off the stack + cosmoV_pop(state); + + // check that it's a number value + if (IS_NUMBER(val)) { + cosmoV_pushValue(state, val); // pushes old value onto the stack :) + if (!cosmoV_set(state, obj, ident, cosmoV_newNumber(cosmoV_readNumber(val) + inc))) + return -1; + } else { + cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val)); + return -1; + } + break; + } } } else { cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp)); diff --git a/src/cvm.h b/src/cvm.h index 898aade..cf7623c 100644 --- a/src/cvm.h +++ b/src/cvm.h @@ -17,7 +17,6 @@ COSMO_API COSMOVMRESULT cosmoV_call(CState *state, int args, int nresults); COSMO_API COSMOVMRESULT cosmoV_pcall(CState *state, int args, int nresults); COSMO_API void cosmoV_makeObject(CState *state, int pairs); COSMO_API void cosmoV_makeDictionary(CState *state, int pairs); -COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, CValue *val); COSMO_API void cosmoV_concat(CState *state, int vals); COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...); COSMO_API void cosmoV_printError(CState *state, CObjError *err); @@ -25,6 +24,9 @@ COSMO_API CObjError* cosmoV_throw(CState *state); COSMO_API void cosmoV_error(CState *state, const char *format, ...); COSMO_API void cosmo_insert(CState *state, int indx, CValue val); +COSMO_API bool cosmoV_get(CState *state, CObj *obj, CValue key, CValue *val); +COSMO_API bool cosmoV_set(CState *state, CObj *obj, CValue key, CValue val); + // nice to have wrappers // pushes value to the stack