mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-11-22 07:20:05 +00:00
Minor VM refactor + GC bug fix
The VM now respects metamethods from proto objects connected to tables. Also the CState is frozen while being instantiated.
This commit is contained in:
parent
0ad0df5fba
commit
fd1481fa43
16
src/cmem.h
16
src/cmem.h
@ -7,13 +7,19 @@
|
|||||||
|
|
||||||
//#define GC_STRESS
|
//#define GC_STRESS
|
||||||
//#define GC_DEBUG
|
//#define GC_DEBUG
|
||||||
// arrays will grow by a factor of 2
|
// arrays *must* grow by a factor of 2
|
||||||
#define GROW_FACTOR 2
|
#define GROW_FACTOR 2
|
||||||
#define HEAP_GROW_FACTOR 2
|
#define HEAP_GROW_FACTOR 2
|
||||||
#define ARRAY_START 8
|
#define ARRAY_START 8
|
||||||
|
|
||||||
|
#ifdef GC_DEBUG
|
||||||
#define cosmoM_freearray(state, type, buf, capacity) \
|
#define cosmoM_freearray(state, type, buf, capacity) \
|
||||||
cosmoM_reallocate(state, buf, sizeof(type) *capacity, 0)
|
printf("freeing array %p [size %lu] at %s:%d\n", buf, sizeof(type) * capacity, __FILE__, __LINE__); \
|
||||||
|
cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0)
|
||||||
|
#else
|
||||||
|
#define cosmoM_freearray(state, type, buf, capacity) \
|
||||||
|
cosmoM_reallocate(state, buf, sizeof(type) * capacity, 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define cosmoM_growarray(state, type, buf, count, capacity) \
|
#define cosmoM_growarray(state, type, buf, count, capacity) \
|
||||||
if (count >= capacity || buf == NULL) { \
|
if (count >= capacity || buf == NULL) { \
|
||||||
@ -22,8 +28,14 @@
|
|||||||
buf = (type*)cosmoM_reallocate(state, buf, sizeof(type) *old, sizeof(type) *capacity); \
|
buf = (type*)cosmoM_reallocate(state, buf, sizeof(type) *old, sizeof(type) *capacity); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef GC_DEBUG
|
||||||
|
#define cosmoM_free(state, type, x) \
|
||||||
|
printf("freeing %p [size %lu] at %s:%d\n", x, sizeof(type), __FILE__, __LINE__); \
|
||||||
|
cosmoM_reallocate(state, x, sizeof(type), 0)
|
||||||
|
#else
|
||||||
#define cosmoM_free(state, type, x) \
|
#define cosmoM_free(state, type, x) \
|
||||||
cosmoM_reallocate(state, x, sizeof(type), 0)
|
cosmoM_reallocate(state, x, sizeof(type), 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define cosmoM_isFrozen(state) \
|
#define cosmoM_isFrozen(state) \
|
||||||
(state->freezeGC > 0)
|
(state->freezeGC > 0)
|
||||||
|
18
src/cstate.c
18
src/cstate.c
@ -16,7 +16,7 @@ CState *cosmoV_newState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
state->panic = false;
|
state->panic = false;
|
||||||
state->freezeGC = false;
|
state->freezeGC = 1; // we start frozen
|
||||||
|
|
||||||
// GC
|
// GC
|
||||||
state->objects = NULL;
|
state->objects = NULL;
|
||||||
@ -38,7 +38,6 @@ CState *cosmoV_newState() {
|
|||||||
for (int i = 0; i < COBJ_MAX; i++)
|
for (int i = 0; i < COBJ_MAX; i++)
|
||||||
state->protoObjects[i] = NULL;
|
state->protoObjects[i] = NULL;
|
||||||
|
|
||||||
// first, set all strings to NULL so our GC doesn't read garbage data
|
|
||||||
for (int i = 0; i < ISTRING_MAX; i++)
|
for (int i = 0; i < ISTRING_MAX; i++)
|
||||||
state->iStrings[i] = NULL;
|
state->iStrings[i] = NULL;
|
||||||
|
|
||||||
@ -68,13 +67,16 @@ CState *cosmoV_newState() {
|
|||||||
for (int i = 0; i < ISTRING_MAX; i++)
|
for (int i = 0; i < ISTRING_MAX; i++)
|
||||||
state->iStrings[i]->isIString = true;
|
state->iStrings[i]->isIString = true;
|
||||||
|
|
||||||
|
state->freezeGC = 0; // unfreeze the state
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoV_freeState(CState *state) {
|
void cosmoV_freeState(CState *state) {
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
printf("state %p is being freed!\n", state);
|
printf("state %p is being free'd!\n", state);
|
||||||
#endif
|
#endif
|
||||||
|
cosmoM_freezeGC(state);
|
||||||
|
|
||||||
// frees all the objects
|
// frees all the objects
|
||||||
CObj *objs = state->objects;
|
CObj *objs = state->objects;
|
||||||
while (objs != NULL) {
|
while (objs != NULL) {
|
||||||
@ -92,7 +94,15 @@ void cosmoV_freeState(CState *state) {
|
|||||||
cosmoT_clearTable(state, &state->globals);
|
cosmoT_clearTable(state, &state->globals);
|
||||||
|
|
||||||
// free our gray stack & finally free the state structure
|
// free our gray stack & finally free the state structure
|
||||||
free(state->grayStack.array);
|
cosmoM_freearray(state, CObj*, state->grayStack.array, state->grayStack.capacity);
|
||||||
|
|
||||||
|
// TODO: yeah idk, it looks like im missing 520 bytes somewhere? i'll look into it later
|
||||||
|
/*#ifdef GC_DEBUG
|
||||||
|
if (state->allocatedBytes != sizeof(CState)) {
|
||||||
|
printf("state->allocatedBytes doesn't match expected value (%lu), got %lu!", sizeof(CState), state->allocatedBytes);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
#endif*/
|
||||||
free(state);
|
free(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
305
src/cvm.c
305
src/cvm.c
@ -691,37 +691,30 @@ int cosmoV_execute(CState *state) {
|
|||||||
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the table
|
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the table
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (IS_OBJ(*temp)) {
|
if (!IS_OBJ(*temp)) {
|
||||||
CValue val; // to hold our value
|
|
||||||
|
|
||||||
switch (cosmoV_readObj(*temp)->type) {
|
|
||||||
case COBJ_TABLE: {
|
|
||||||
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
|
|
||||||
|
|
||||||
cosmoT_get(&tbl->tbl, *key, &val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cosmoV_setTop(state, 2); // pops the table & the key
|
|
||||||
cosmoV_pushValue(state, val); // pushes the field result
|
|
||||||
} else {
|
|
||||||
cosmoV_error(state, "Couldn't index type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't index type %s!", cosmoV_typeStr(*temp));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CObj *obj = cosmoV_readObj(*temp);
|
||||||
|
CObjObject *proto = cosmoO_grabProto(obj);
|
||||||
|
CValue val; // to hold our value
|
||||||
|
|
||||||
|
if (proto != NULL) {
|
||||||
|
// check for __index metamethod
|
||||||
|
if (!cosmoO_indexObject(state, proto, *key, &val)) // if returns false, cosmoV_error was called
|
||||||
|
return -1;
|
||||||
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
|
CObjTable *tbl = (CObjTable*)obj;
|
||||||
|
|
||||||
|
cosmoT_get(&tbl->tbl, *key, &val);
|
||||||
|
} else {
|
||||||
|
cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cosmoV_setTop(state, 2); // pops the table & the key
|
||||||
|
cosmoV_pushValue(state, val); // pushes the field result
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case OP_NEWINDEX: {
|
case OP_NEWINDEX: {
|
||||||
@ -730,37 +723,29 @@ int cosmoV_execute(CState *state) {
|
|||||||
StkPtr temp = cosmoV_getTop(state, 2); // table is after the key
|
StkPtr temp = cosmoV_getTop(state, 2); // table is after the key
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (IS_OBJ(*temp)) {
|
if (!IS_OBJ(*temp)) {
|
||||||
switch (cosmoV_readObj(*temp)->type) {
|
|
||||||
case COBJ_TABLE: { // index and set table
|
|
||||||
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
|
|
||||||
CValue *newVal = cosmoT_insert(state, &tbl->tbl, *key);
|
|
||||||
|
|
||||||
*newVal = *value; // set the index
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pop everything off the stack
|
|
||||||
cosmoV_setTop(state, 3);
|
|
||||||
} else {
|
|
||||||
cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CObj *obj = cosmoV_readObj(*temp);
|
||||||
|
CObjObject *proto = cosmoO_grabProto(obj);
|
||||||
|
|
||||||
|
if (proto != NULL) {
|
||||||
|
if (!cosmoO_newIndexObject(state, proto, *key, *value)) // if it returns false, cosmoV_error was called
|
||||||
|
return -1;
|
||||||
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
|
CObjTable *tbl = (CObjTable*)obj;
|
||||||
|
CValue *newVal = cosmoT_insert(state, &tbl->tbl, *key);
|
||||||
|
|
||||||
|
*newVal = *value; // set the index
|
||||||
|
} else {
|
||||||
|
cosmoV_error(state, "No proto defined! Couldn't __newindex from type %s", cosmoV_typeStr(*temp));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop everything off the stack
|
||||||
|
cosmoV_setTop(state, 3);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case OP_NEWOBJECT: {
|
case OP_NEWOBJECT: {
|
||||||
@ -856,63 +841,56 @@ int cosmoV_execute(CState *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CObj *obj = cosmoV_readObj(*temp);
|
CObj *obj = cosmoV_readObj(*temp);
|
||||||
switch (obj->type) {
|
CObjObject *proto = cosmoO_grabProto(obj);
|
||||||
case COBJ_TABLE: {
|
CValue val;
|
||||||
CObjTable *tbl = (CObjTable*)obj;
|
|
||||||
|
|
||||||
cosmoV_pushValue(state, cosmoV_newObj(state->iStrings[ISTRING_RESERVED])); // key
|
if (proto != NULL) {
|
||||||
cosmoV_pushValue(state, cosmoV_newObj(tbl)); // value
|
// grab __iter & call it
|
||||||
|
if (cosmoO_getIString(state, proto, ISTRING_ITER, &val)) {
|
||||||
|
cosmoV_pop(state); // pop the object from the stack
|
||||||
|
cosmoV_pushValue(state, val);
|
||||||
|
cosmoV_pushValue(state, cosmoV_newObj(obj));
|
||||||
|
if (cosmoV_call(state, 1, 1) != COSMOVM_OK) // we expect 1 return value on the stack, the iterable object
|
||||||
|
return -1;
|
||||||
|
|
||||||
cosmoV_pushString(state, "__next"); // key
|
StkPtr iObj = cosmoV_getTop(state, 0);
|
||||||
CObjCFunction *tbl_next = cosmoO_newCFunction(state, _tbl__next);
|
|
||||||
cosmoV_pushValue(state, cosmoV_newObj(tbl_next)); // value
|
|
||||||
|
|
||||||
cosmoV_makeObject(state, 2); // pushes the new object to the stack
|
if (!IS_OBJECT(*iObj)) {
|
||||||
|
cosmoV_error(state, "Expected iterable object! '__iter' returned %s, expected <object>!", cosmoV_typeStr(*iObj));
|
||||||
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_newMethod(state, cosmoV_newObj(tbl_next), (CObj*)obj);
|
|
||||||
|
|
||||||
cosmoV_setTop(state, 2); // pops the object & the tbl
|
|
||||||
cosmoV_pushValue(state, cosmoV_newObj(method)); // pushes the method for OP_NEXT
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// grab __iter & call it
|
// get __next method and place it at the top of the stack
|
||||||
if (cosmoO_getIString(state, object, ISTRING_ITER, &val)) {
|
cosmoV_getMethod(state, cosmoV_readObj(*iObj), cosmoV_newObj(state->iStrings[ISTRING_NEXT]), iObj);
|
||||||
cosmoV_pop(state); // pop the object from the stack
|
} else {
|
||||||
cosmoV_pushValue(state, val);
|
cosmoV_error(state, "Expected iterable object! '__iter' not defined!");
|
||||||
cosmoV_pushValue(state, cosmoV_newObj(obj));
|
return -1;
|
||||||
if (cosmoV_call(state, 1, 1) != COSMOVM_OK) // we expect 1 return value on the stack, the iterable object
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
StkPtr iObj = cosmoV_getTop(state, 0);
|
|
||||||
|
|
||||||
if (!IS_OBJECT(*iObj)) {
|
|
||||||
cosmoV_error(state, "Expected iterable object! '__iter' returned %s, expected <object>!", cosmoV_typeStr(*iObj));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get __next method and place it at the top of the stack
|
|
||||||
cosmoV_getMethod(state, cosmoV_readObj(*iObj), cosmoV_newObj(state->iStrings[ISTRING_NEXT]), iObj);
|
|
||||||
} else {
|
|
||||||
cosmoV_error(state, "Expected iterable object! '__iter' not defined!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
|
CObjTable *tbl = (CObjTable*)obj;
|
||||||
|
|
||||||
|
cosmoV_pushValue(state, cosmoV_newObj(state->iStrings[ISTRING_RESERVED])); // key
|
||||||
|
cosmoV_pushValue(state, cosmoV_newObj(tbl)); // value
|
||||||
|
|
||||||
|
cosmoV_pushString(state, "__next"); // key
|
||||||
|
CObjCFunction *tbl_next = cosmoO_newCFunction(state, _tbl__next);
|
||||||
|
cosmoV_pushValue(state, cosmoV_newObj(tbl_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_newMethod(state, cosmoV_newObj(tbl_next), (CObj*)obj);
|
||||||
|
|
||||||
|
cosmoV_setTop(state, 2); // pops the object & the tbl
|
||||||
|
cosmoV_pushValue(state, cosmoV_newObj(method)); // pushes the method for OP_NEXT
|
||||||
|
} else {
|
||||||
|
cosmoV_error(state, "No proto defined! Couldn't get from type %s", cosmoO_typeStr(obj));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case OP_NEXT: {
|
case OP_NEXT: {
|
||||||
@ -1052,53 +1030,45 @@ int cosmoV_execute(CState *state) {
|
|||||||
StkPtr temp = cosmoV_getTop(state, 1); // object should be above the key
|
StkPtr temp = cosmoV_getTop(state, 1); // object should be above the key
|
||||||
StkPtr key = cosmoV_getTop(state, 0); // grabs key
|
StkPtr key = cosmoV_getTop(state, 0); // grabs key
|
||||||
|
|
||||||
if (IS_OBJ(*temp)) {
|
if (!IS_OBJ(*temp)) {
|
||||||
switch (cosmoV_readObj(*temp)->type) {
|
cosmoV_error(state, "Couldn't index non-indexable type %s!", cosmoV_typeStr(*temp));
|
||||||
case COBJ_TABLE: {
|
return -1;
|
||||||
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
|
}
|
||||||
CValue *val = cosmoT_insert(state, &tbl->tbl, *key);
|
|
||||||
|
|
||||||
// pops tbl & key from stack
|
CObj *obj = cosmoV_readObj(*temp);
|
||||||
cosmoV_setTop(state, 2);
|
CObjObject *proto = cosmoO_grabProto(obj);
|
||||||
|
CValue val;
|
||||||
|
|
||||||
if (IS_NUMBER(*val)) {
|
// call __index if the proto was found
|
||||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
if (proto != NULL) {
|
||||||
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
if (cosmoO_indexObject(state, proto, *key, &val)) {
|
||||||
} else {
|
if (!IS_NUMBER(val)) {
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default: {
|
|
||||||
CObjObject *object = cosmoO_grabProto(cosmoV_readObj(*temp));
|
|
||||||
CValue val;
|
|
||||||
|
|
||||||
if (object == NULL) {
|
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
|
||||||
cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// call __index
|
// call __newindex
|
||||||
if (cosmoO_indexObject(state, object, *key, &val)) {
|
if (!cosmoO_newIndexObject(state, proto, *key, cosmoV_newNumber(cosmoV_readNumber(val) + inc)))
|
||||||
if (IS_NUMBER(val)) {
|
return -1;
|
||||||
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
|
} else
|
||||||
|
return -1; // cosmoO_indexObject failed and threw an error
|
||||||
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
|
CObjTable *tbl = (CObjTable*)obj;
|
||||||
|
CValue *val = cosmoT_insert(state, &tbl->tbl, *key);
|
||||||
|
|
||||||
// call __newindex
|
if (!IS_NUMBER(*val)) {
|
||||||
if (!cosmoO_newIndexObject(state, object, *key, cosmoV_newNumber(cosmoV_readNumber(val) + inc)))
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pops tbl & key from stack
|
||||||
|
cosmoV_setTop(state, 2);
|
||||||
|
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
||||||
|
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc); // sets table index
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1112,44 +1082,23 @@ int cosmoV_execute(CState *state) {
|
|||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if (IS_OBJ(*temp)) {
|
if (IS_OBJ(*temp)) {
|
||||||
switch (cosmoV_readObj(*temp)->type) {
|
CObj *obj = cosmoV_readObj(*temp);
|
||||||
case COBJ_TABLE: {
|
CValue val;
|
||||||
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
|
|
||||||
CValue *val = cosmoT_insert(state, &tbl->tbl, ident);
|
|
||||||
|
|
||||||
// pops tbl from stack
|
if (!cosmoV_get(state, obj, ident, &val))
|
||||||
cosmoV_pop(state);
|
return -1;
|
||||||
|
|
||||||
if (IS_NUMBER(*val)) {
|
// pop the object off the stack
|
||||||
cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
|
cosmoV_pop(state);
|
||||||
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
|
|
||||||
} else {
|
|
||||||
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
CObj *obj = cosmoV_readObj(*temp);
|
|
||||||
CValue val;
|
|
||||||
|
|
||||||
if (!cosmoV_get(state, obj, ident, &val))
|
// check that it's a number value
|
||||||
return -1;
|
if (IS_NUMBER(val)) {
|
||||||
|
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
|
||||||
// pop the object off the stack
|
if (!cosmoV_set(state, obj, ident, cosmoV_newNumber(cosmoV_readNumber(val) + inc)))
|
||||||
cosmoV_pop(state);
|
return -1;
|
||||||
|
} else {
|
||||||
// check that it's a number value
|
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
|
||||||
if (IS_NUMBER(val)) {
|
return -1;
|
||||||
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 {
|
} else {
|
||||||
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
|
||||||
|
Loading…
Reference in New Issue
Block a user