added support for NaN boxing (8 byte CValues!)

This commit is contained in:
CPunch 2020-12-04 00:04:14 -06:00
parent 495f1d7272
commit b936827cc6
8 changed files with 148 additions and 83 deletions

View File

@ -98,7 +98,7 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
int index = readu16Chunk(chunk, offset + 1); int index = readu16Chunk(chunk, offset + 1);
printf("%-16s [%05d] - ", "OP_CLOSURE", index); printf("%-16s [%05d] - ", "OP_CLOSURE", index);
CValue val = chunk->constants.values[index]; CValue val = chunk->constants.values[index];
CObjFunction *cobjFunc = (CObjFunction*)val.val.obj; CObjFunction *cobjFunc = (CObjFunction*)cosmoV_readObj(val);
offset += 3; // we consumed the opcode + u16 offset += 3; // we consumed the opcode + u16
printValue(val); printValue(val);

View File

@ -71,7 +71,7 @@ void tableRemoveWhite(CState *state, CTable *tbl) {
for (int i = 0; i < tbl->capacity; i++) { for (int i = 0; i < tbl->capacity; i++) {
CTableEntry *entry = &tbl->table[i]; CTableEntry *entry = &tbl->table[i];
if (IS_OBJ(entry->key) && !(entry->key.val.obj)->isMarked) { // if the key is a object and it's white (unmarked), remove it from the table if (IS_OBJ(entry->key) && !(cosmoV_readObj(entry->key))->isMarked) { // if the key is a object and it's white (unmarked), remove it from the table
cosmoT_remove(state, tbl, entry->key); cosmoT_remove(state, tbl, entry->key);
} }
} }

View File

@ -90,12 +90,12 @@ typedef struct CObjUpval {
#define IS_METHOD(x) isObjType(x, COBJ_METHOD) #define IS_METHOD(x) isObjType(x, COBJ_METHOD)
#define IS_CLOSURE(x) isObjType(x, COBJ_CLOSURE) #define IS_CLOSURE(x) isObjType(x, COBJ_CLOSURE)
#define cosmoV_readString(x) ((CObjString*)cosmoV_readObj((x))) #define cosmoV_readString(x) ((CObjString*)cosmoV_readObj(x))
#define cosmoV_readObject(x) ((CObjObject*)cosmoV_readObj((x))) #define cosmoV_readObject(x) ((CObjObject*)cosmoV_readObj(x))
#define cosmoV_readFunction(x) ((CObjFunction*)cosmoV_readObj((x))) #define cosmoV_readFunction(x) ((CObjFunction*)cosmoV_readObj(x))
#define cosmoV_readCFunction(x) (((CObjCFunction*)cosmoV_readObj((x)))->cfunc) #define cosmoV_readCFunction(x) (((CObjCFunction*)cosmoV_readObj(x))->cfunc)
#define cosmoV_readMethod(x) ((CObjMethod*)cosmoV_readObj((x))) #define cosmoV_readMethod(x) ((CObjMethod*)cosmoV_readObj(x))
#define cosmoV_readClosure(x) ((CObjClosure*)cosmoV_readObj((x))) #define cosmoV_readClosure(x) ((CObjClosure*)cosmoV_readObj(x))
static inline bool isObjType(CValue val, CObjType type) { static inline bool isObjType(CValue val, CObjType type) {
return IS_OBJ(val) && cosmoV_readObj(val)->type == type; return IS_OBJ(val) && cosmoV_readObj(val)->type == type;

View File

@ -7,10 +7,16 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
//#define NAN_BOXXED
// forward declare *most* stuff so our headers are cleaner // forward declare *most* stuff so our headers are cleaner
typedef struct CState CState; typedef struct CState CState;
typedef struct CChunk CChunk; typedef struct CChunk CChunk;
#ifdef NAN_BOXXED
typedef union CValue CValue;
#else
typedef struct CValue CValue; typedef struct CValue CValue;
#endif
// objs // objs
typedef struct CObj CObj; typedef struct CObj CObj;

View File

@ -62,18 +62,20 @@ uint32_t getObjectHash(CObj *obj) {
} }
uint32_t getValueHash(CValue *val) { uint32_t getValueHash(CValue *val) {
switch (val->type) { switch (GET_TYPE(*val)) {
case COSMO_TOBJ: case COSMO_TOBJ:
return getObjectHash(val->val.obj); return getObjectHash(cosmoV_readObj(*val));
case COSMO_TNUMBER: { case COSMO_TNUMBER: {
uint32_t buf[sizeof(cosmo_Number)/sizeof(uint32_t)]; uint32_t buf[sizeof(cosmo_Number)/sizeof(uint32_t)];
if (val->val.num == 0) cosmo_Number num = cosmoV_readNumber(*val);
if (num == 0)
return 0; return 0;
memcpy(buf, &val->val.num, sizeof(buf));
memcpy(buf, &num, sizeof(buf));
for (int i = 0; i < sizeof(cosmo_Number)/sizeof(uint32_t); i++) buf[0] += buf[i]; for (int i = 0; i < sizeof(cosmo_Number)/sizeof(uint32_t); i++) buf[0] += buf[i];
return buf[0]; return buf[0];
} }
// TODO: add support for other types // TODO: add support for other types
default: default:
return 0; return 0;
@ -227,7 +229,7 @@ CObjString *cosmoT_lookupString(CTable *tbl, const char *str, size_t length, uin
return NULL; return NULL;
} else if (IS_STRING(entry->key) && cosmoV_readString(entry->key)->length == length && memcmp(cosmoV_readString(entry->key)->str, str, length) == 0) { } else if (IS_STRING(entry->key) && cosmoV_readString(entry->key)->length == length && memcmp(cosmoV_readString(entry->key)->str, str, length) == 0) {
// it's a match! // it's a match!
return (CObjString*)entry->key.val.obj; return (CObjString*)cosmoV_readObj(entry->key);
} }
indx = (indx + 1) & (tbl->capacity - 1); // fast mod here too indx = (indx + 1) & (tbl->capacity - 1); // fast mod here too

View File

@ -1,3 +1,4 @@
#include "cosmo.h"
#include "cmem.h" #include "cmem.h"
#include "cvalue.h" #include "cvalue.h"
#include "cobj.h" #include "cobj.h"
@ -19,14 +20,14 @@ void appendValArray(CState *state, CValueArray *array, CValue val) {
} }
bool cosmoV_equal(CValue valA, CValue valB) { bool cosmoV_equal(CValue valA, CValue valB) {
if (valA.type != valB.type) // are they the same type? if (GET_TYPE(valA) != GET_TYPE(valB)) // are they the same type?
return false; return false;
// compare // compare
switch (valA.type) { switch (GET_TYPE(valA)) {
case COSMO_TBOOLEAN: return valA.val.b == valB.val.b; case COSMO_TBOOLEAN: return cosmoV_readBoolean(valA) == cosmoV_readBoolean(valB);
case COSMO_TNUMBER: return valA.val.num == valB.val.num; case COSMO_TNUMBER: return cosmoV_readNumber(valA) == cosmoV_readNumber(valB);
case COSMO_TOBJ: return cosmoO_equal(valA.val.obj, valB.val.obj); case COSMO_TOBJ: return cosmoO_equal(cosmoV_readObj(valA), cosmoV_readObj(valB));
case COSMO_TNIL: return true; case COSMO_TNIL: return true;
default: default:
return false; return false;
@ -34,17 +35,17 @@ bool cosmoV_equal(CValue valA, CValue valB) {
} }
CObjString *cosmoV_toString(CState *state, CValue val) { CObjString *cosmoV_toString(CState *state, CValue val) {
switch (val.type) { switch (GET_TYPE(val)) {
case COSMO_TNUMBER: { case COSMO_TNUMBER: {
char buf[32]; char buf[32];
int size = snprintf((char*)&buf, 32, "%.14g", val.val.num); int size = snprintf((char*)&buf, 32, "%.14g", cosmoV_readNumber(val));
return cosmoO_copyString(state, (char*)&buf, size); return cosmoO_copyString(state, (char*)&buf, size);
} }
case COSMO_TBOOLEAN: { case COSMO_TBOOLEAN: {
return val.val.b ? cosmoO_copyString(state, "true", 4) : cosmoO_copyString(state, "false", 5); return cosmoV_readBoolean(val) ? cosmoO_copyString(state, "true", 4) : cosmoO_copyString(state, "false", 5);
} }
case COSMO_TOBJ: { case COSMO_TOBJ: {
return cosmoO_toString(state, val.val.obj); return cosmoO_toString(state, cosmoV_readObj(val));
} }
case COSMO_TNIL: { case COSMO_TNIL: {
return cosmoO_copyString(state, "nil", 3); return cosmoO_copyString(state, "nil", 3);
@ -55,11 +56,11 @@ CObjString *cosmoV_toString(CState *state, CValue val) {
} }
const char *cosmoV_typeStr(CValue val) { const char *cosmoV_typeStr(CValue val) {
switch (val.type) { switch (GET_TYPE(val)) {
case COSMO_TNIL: return "<nil>"; case COSMO_TNIL: return "<nil>";
case COSMO_TBOOLEAN: return "<bool>"; case COSMO_TBOOLEAN: return "<bool>";
case COSMO_TNUMBER: return "<number>"; case COSMO_TNUMBER: return "<number>";
case COSMO_TOBJ: return cosmoO_typeStr(val.val.obj); case COSMO_TOBJ: return cosmoO_typeStr(cosmoV_readObj(val));
default: default:
return "<unkn val>"; return "<unkn val>";
@ -67,15 +68,15 @@ const char *cosmoV_typeStr(CValue val) {
} }
void printValue(CValue val) { void printValue(CValue val) {
switch (val.type) { switch (GET_TYPE(val)) {
case COSMO_TNUMBER: case COSMO_TNUMBER:
printf("%g", val.val.num); printf("%g", cosmoV_readNumber(val));
break; break;
case COSMO_TBOOLEAN: case COSMO_TBOOLEAN:
printf(cosmoV_readBoolean(val) ? "true" : "false"); printf(cosmoV_readBoolean(val) ? "true" : "false");
break; break;
case COSMO_TOBJ: { case COSMO_TOBJ: {
printObject(val.val.obj); printObject(cosmoV_readObj(val));
break; break;
} }
case COSMO_TNIL: case COSMO_TNIL:

View File

@ -4,10 +4,10 @@
#include "cosmo.h" #include "cosmo.h"
typedef enum { typedef enum {
COSMO_TNIL, COSMO_TNUMBER, // number has to be 0 because NaN box
COSMO_TBOOLEAN, COSMO_TBOOLEAN,
COSMO_TNUMBER, COSMO_TOBJ,
COSMO_TOBJ COSMO_TNIL,
} CosmoType; } CosmoType;
typedef double cosmo_Number; typedef double cosmo_Number;
@ -15,6 +15,57 @@ typedef double cosmo_Number;
/* /*
holds primitive cosmo types holds primitive cosmo types
*/ */
#ifdef NAN_BOXXED
/*
NaN box, this is great for performance on x86_64 or ARM64 architectures. If you don't know how this works please reference these
two articles:
https://leonardschuetz.ch/blog/nan-boxing/ and https://piotrduperas.com/posts/nan-boxing/
both are great resources :)
TL;DR: we can store payloads in the NaN value in the IEEE 754 standard.
*/
typedef union CValue {
uint64_t data;
cosmo_Number num;
} CValue;
#define MASK_SIGN_BIT ((uint64_t)1 << 63)
#define MASK_TYPE ((uint64_t)0xf)
#define MASK_PAYLOAD ((uint64_t)0xfffffffffff0)
#define MAKE_PAYLOAD(x) ((uint64_t)(x) << 4)
// The bits that must be set to indicate a quiet NaN.
#define MASK_QUIETNAN ((uint64_t)0x7ffc000000000000)
// sadly this requires a bit more than a simple macro :(
static inline CosmoType GET_TYPE(CValue val) {
// it's not not a number (its a number)
if ((((val.data) & MASK_QUIETNAN) != MASK_QUIETNAN))
return COSMO_TNUMBER;
if ((((val.data) & (MASK_QUIETNAN | MASK_SIGN_BIT)) == (MASK_QUIETNAN | MASK_SIGN_BIT)))
return COSMO_TOBJ;
return (val.data & MASK_TYPE);
}
#define cosmoV_newNumber(x) ((CValue){.num = x})
#define cosmoV_newObj(x) ((CValue){.data = MASK_SIGN_BIT | MASK_QUIETNAN | (uint64_t)(uintptr_t)(x)})
#define cosmoV_newBoolean(x) ((CValue){.data = MASK_QUIETNAN | MAKE_PAYLOAD(x) | COSMO_TBOOLEAN})
#define cosmoV_newNil() ((CValue){.data = MASK_QUIETNAN | COSMO_TNIL})
#define cosmoV_readNumber(x) ((x).num)
#define cosmoV_readBoolean(x) ((bool)((x).data & MASK_PAYLOAD))
#define cosmoV_readObj(x) (((CObj*)(uintptr_t)(((x).data) & ~(MASK_SIGN_BIT | MASK_QUIETNAN))))
#else
/*
Tagged union, this is the best platform independent solution
*/
typedef struct CValue { typedef struct CValue {
CosmoType type; CosmoType type;
union { union {
@ -23,6 +74,29 @@ typedef struct CValue {
CObj *obj; CObj *obj;
} val; } val;
} CValue; } CValue;
#define GET_TYPE(x) ((x).type)
// create CValues
#define cosmoV_newNumber(x) ((CValue){COSMO_TNUMBER, {.num = (x)}})
#define cosmoV_newBoolean(x) ((CValue){COSMO_TBOOLEAN, {.b = (x)}})
#define cosmoV_newObj(x) ((CValue){COSMO_TOBJ, {.obj = (CObj*)(x)}})
#define cosmoV_newNil() ((CValue){COSMO_TNIL, {.num = 0}})
// read CValues
#define cosmoV_readNumber(x) ((cosmo_Number)(x).val.num)
#define cosmoV_readBoolean(x) ((bool)(x).val.b)
#define cosmoV_readObj(x) ((CObj*)(x).val.obj)
#endif
#define IS_NUMBER(x) (GET_TYPE(x) == COSMO_TNUMBER)
#define IS_BOOLEAN(x) (GET_TYPE(x) == COSMO_TBOOLEAN)
#define IS_NIL(x) (GET_TYPE(x) == COSMO_TNIL)
#define IS_OBJ(x) (GET_TYPE(x) == COSMO_TOBJ)
typedef CValue* StkPtr; typedef CValue* StkPtr;
typedef struct CValueArray { typedef struct CValueArray {
@ -40,22 +114,4 @@ COSMO_API bool cosmoV_equal(CValue valA, CValue valB);
COSMO_API CObjString *cosmoV_toString(CState *state, CValue val); COSMO_API CObjString *cosmoV_toString(CState *state, CValue val);
COSMO_API const char *cosmoV_typeStr(CValue val); // return constant char array for corresponding type COSMO_API const char *cosmoV_typeStr(CValue val); // return constant char array for corresponding type
#define IS_NUMBER(x) (x.type == COSMO_TNUMBER)
#define IS_BOOLEAN(x) (x.type == COSMO_TBOOLEAN)
#define IS_NIL(x) (x.type == COSMO_TNIL)
#define IS_OBJ(x) (x.type == COSMO_TOBJ)
// create CValues
#define cosmoV_newNumber(x) ((CValue){COSMO_TNUMBER, {.num = x}})
#define cosmoV_newBoolean(x) ((CValue){COSMO_TBOOLEAN, {.b = x}})
#define cosmoV_newObj(x) ((CValue){COSMO_TOBJ, {.obj = (CObj*)x}})
#define cosmoV_newNil() ((CValue){COSMO_TNIL, {.num = 0}})
// read CValues
#define cosmoV_readNumber(x) ((cosmo_Number)x.val.num)
#define cosmoV_readBoolean(x) ((bool)x.val.b)
#define cosmoV_readObj(x) ((CObj*)x.val.obj)
#endif #endif

View File

@ -164,26 +164,26 @@ bool invokeMethod(CState* state, CObjObject *obj, CValue func, int args) {
COSMOVMRESULT cosmoV_call(CState *state, int args) { COSMOVMRESULT cosmoV_call(CState *state, int args) {
StkPtr val = cosmoV_getTop(state, args); // function will always be right above the args StkPtr val = cosmoV_getTop(state, args); // function will always be right above the args
if (val->type != COSMO_TOBJ) { if (GET_TYPE(*val) != COSMO_TOBJ) {
cosmoV_error(state, "Cannot call non-function type %s!", cosmoV_typeStr(*val)); cosmoV_error(state, "Cannot call non-function type %s!", cosmoV_typeStr(*val));
return COSMOVM_RUNTIME_ERR; return COSMOVM_RUNTIME_ERR;
} }
switch (val->val.obj->type) { switch (cosmoV_readObj(*val)->type) {
case COBJ_CLOSURE: { case COBJ_CLOSURE: {
CObjClosure *closure = (CObjClosure*)(val->val.obj); CObjClosure *closure = (CObjClosure*)cosmoV_readObj(*val);
if (!call(state, closure, args, 0)) { if (!call(state, closure, args, 0)) {
return COSMOVM_RUNTIME_ERR; return COSMOVM_RUNTIME_ERR;
} }
break; break;
} }
case COBJ_METHOD: { case COBJ_METHOD: {
CObjMethod *method = (CObjMethod*)val->val.obj; CObjMethod *method = (CObjMethod*)cosmoV_readObj(*val);
invokeMethod(state, method->obj, method->func, args); invokeMethod(state, method->obj, method->func, args);
break; break;
} }
case COBJ_OBJECT: { case COBJ_OBJECT: {
CObjObject *protoObj = (CObjObject*)val->val.obj; CObjObject *protoObj = (CObjObject*)cosmoV_readObj(*val);
CObjObject *newObj = cosmoO_newObject(state); CObjObject *newObj = cosmoO_newObject(state);
newObj->proto = protoObj; newObj->proto = protoObj;
CValue ret; CValue ret;
@ -205,7 +205,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
} }
case COBJ_CFUNCTION: { case COBJ_CFUNCTION: {
// it's a C function, so call it // it's a C function, so call it
CosmoCFunction cfunc = ((CObjCFunction*)(val->val.obj))->cfunc; CosmoCFunction cfunc = ((CObjCFunction*)cosmoV_readObj(*val))->cfunc;
callCFunction(state, cfunc, args, 0); callCFunction(state, cfunc, args, 0);
break; break;
} }
@ -218,7 +218,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
} }
static inline bool isFalsey(StkPtr val) { static inline bool isFalsey(StkPtr val) {
return val->type == COSMO_TNIL || (val->type == COSMO_TBOOLEAN && !val->val.b); return IS_NIL(*val) || (IS_BOOLEAN(*val) && !cosmoV_readBoolean(*val));
} }
COSMO_API void cosmoV_pushObject(CState *state, int pairs) { COSMO_API void cosmoV_pushObject(CState *state, int pairs) {
@ -242,12 +242,12 @@ COSMO_API void cosmoV_pushObject(CState *state, int pairs) {
COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, CValue *val) { COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, CValue *val) {
if (cosmoO_getObject(state, object, key, val)) { if (cosmoO_getObject(state, object, key, val)) {
if (val->type == COSMO_TOBJ ) { if (IS_OBJ(*val)) {
if (val->val.obj->type == COBJ_CLOSURE) { // is it a function? if so, make it a method to the current object 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*)val->val.obj, object); CObjMethod *method = cosmoO_newMethod(state, (CObjClosure*)cosmoV_readObj(*val), object);
*val = cosmoV_newObj(method); *val = cosmoV_newObj(method);
} else if (val->val.obj->type == COBJ_CFUNCTION) { } else if (cosmoV_readObj(*val)->type == COBJ_CFUNCTION) {
CObjMethod *method = cosmoO_newCMethod(state, (CObjCFunction*)val->val.obj, object); CObjMethod *method = cosmoO_newCMethod(state, (CObjCFunction*)cosmoV_readObj(*val), object);
*val = cosmoV_newObj(method); *val = cosmoV_newObj(method);
} }
} }
@ -261,9 +261,9 @@ COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, C
#define NUMBEROP(typeConst, op) \ #define NUMBEROP(typeConst, op) \
StkPtr valA = cosmoV_getTop(state, 1); \ StkPtr valA = cosmoV_getTop(state, 1); \
StkPtr valB = cosmoV_getTop(state, 0); \ StkPtr valB = cosmoV_getTop(state, 0); \
if (valA->type == COSMO_TNUMBER && valB->type == COSMO_TNUMBER) { \ if (IS_NUMBER(*valA) && IS_NUMBER(*valB)) { \
cosmoV_setTop(state, 2); /* pop the 2 values */ \ cosmoV_setTop(state, 2); /* pop the 2 values */ \
cosmoV_pushValue(state, typeConst((valA->val.num) op (valB->val.num))); \ cosmoV_pushValue(state, typeConst(cosmoV_readNumber(*valA) op cosmoV_readNumber(*valB))); \
} else { \ } else { \
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA), cosmoV_typeStr(*valB)); \ cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA), cosmoV_typeStr(*valB)); \
} \ } \
@ -393,12 +393,12 @@ bool cosmoV_execute(CState *state) {
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the object StkPtr temp = cosmoV_getTop(state, 1); // after that should be the object
// sanity check // sanity check
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) { if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp)); cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp));
break; break;
} }
CObjObject *object = (CObjObject*)temp->val.obj; CObjObject *object = (CObjObject*)cosmoV_readObj(*temp);
CValue val; // to hold our value CValue val; // to hold our value
cosmoV_getObject(state, object, *key, &val); cosmoV_getObject(state, object, *key, &val);
@ -412,12 +412,12 @@ bool cosmoV_execute(CState *state) {
StkPtr temp = cosmoV_getTop(state, 2); // object is after the key StkPtr temp = cosmoV_getTop(state, 2); // object is after the key
// sanity check // sanity check
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) { if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
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));
break; break;
} }
CObjObject *object = (CObjObject*)temp->val.obj; CObjObject *object = (CObjObject*)cosmoV_readObj(*temp);
cosmoO_setObject(state, object, *key, *value); cosmoO_setObject(state, object, *key, *value);
// pop everything off the stack // pop everything off the stack
@ -430,12 +430,12 @@ bool cosmoV_execute(CState *state) {
StkPtr temp = cosmoV_getTop(state, args+1); // grabs object from stack StkPtr temp = cosmoV_getTop(state, args+1); // grabs object from stack
// sanity check // sanity check
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) { if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
cosmoV_error(state, "Couldn't get from non-object type %s!", cosmoV_typeStr(*temp)); cosmoV_error(state, "Couldn't get from non-object type %s!", cosmoV_typeStr(*temp));
break; break;
} }
CObjObject *object = (CObjObject*)temp->val.obj; CObjObject *object = (CObjObject*)cosmoV_readObj(*temp);
CValue val; // to hold our value CValue val; // to hold our value
cosmoO_getObject(state, object, *key, &val); // we use cosmoO_getObject instead of the cosmoV_getObject wrapper so we get the raw value from the object instead of the CObjMethod wrapper cosmoO_getObject(state, object, *key, &val); // we use cosmoO_getObject instead of the cosmoV_getObject wrapper so we get the raw value from the object instead of the CObjMethod wrapper
@ -471,9 +471,9 @@ bool cosmoV_execute(CState *state) {
case OP_NEGATE: { // pop 1 value off the stack & try to negate case OP_NEGATE: { // pop 1 value off the stack & try to negate
StkPtr val = cosmoV_getTop(state, 0); StkPtr val = cosmoV_getTop(state, 0);
if (val->type == COSMO_TNUMBER) { if (IS_NUMBER(*val)) {
cosmoV_pop(state); cosmoV_pop(state);
cosmoV_pushNumber(state, -(val->val.num)); cosmoV_pushNumber(state, -(cosmoV_readNumber(*val)));
} else { } else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val)); cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
} }
@ -482,12 +482,12 @@ bool cosmoV_execute(CState *state) {
case OP_COUNT: { // pop 1 value off the stack & if it's an object return the ammount of active entries it has case OP_COUNT: { // pop 1 value off the stack & if it's an object return the ammount of active entries it has
StkPtr temp = cosmoV_getTop(state, 0); StkPtr temp = cosmoV_getTop(state, 0);
if (temp->type != COSMO_TOBJ || ((CObj*)temp->val.obj)->type != COBJ_OBJECT) { if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
cosmoV_error(state, "Expected object, got %s!", cosmoV_typeStr(*temp)); cosmoV_error(state, "Expected object, got %s!", cosmoV_typeStr(*temp));
break; break;
} }
CObjObject *obj = (CObjObject*)temp->val.obj; CObjObject *obj = (CObjObject*)cosmoV_readObj(*temp);
cosmoV_pop(state); cosmoV_pop(state);
cosmoV_pushNumber(state, cosmoT_count(&obj->tbl)); // pushes the count onto the stack cosmoV_pushNumber(state, cosmoT_count(&obj->tbl)); // pushes the count onto the stack
break; break;
@ -517,9 +517,9 @@ bool cosmoV_execute(CState *state) {
StkPtr val = &frame->base[indx]; StkPtr val = &frame->base[indx];
// check that it's a number value // check that it's a number value
if (val->type == COSMO_TNUMBER) { if (IS_NUMBER(*val)) {
cosmoV_pushValue(state, *val); // pushes old value onto the stack :) cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
*val = cosmoV_newNumber(val->val.num + inc); *val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
} else { } else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val)); cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
} }
@ -533,9 +533,9 @@ bool cosmoV_execute(CState *state) {
CValue *val = cosmoT_insert(state, &state->globals, ident); CValue *val = cosmoT_insert(state, &state->globals, ident);
// check that it's a number value // check that it's a number value
if (val->type == COSMO_TNUMBER) { if (IS_NUMBER(*val)) {
cosmoV_pushValue(state, *val); // pushes old value onto the stack :) cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
*val = cosmoV_newNumber(val->val.num + inc); *val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
} else { } else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val)); cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
} }
@ -548,9 +548,9 @@ bool cosmoV_execute(CState *state) {
CValue *val = frame->closure->upvalues[indx]->val; CValue *val = frame->closure->upvalues[indx]->val;
// check that it's a number value // check that it's a number value
if (val->type == COSMO_TNUMBER) { if (IS_NUMBER(*val)) {
cosmoV_pushValue(state, *val); // pushes old value onto the stack :) cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
*val = cosmoV_newNumber(val->val.num + inc); *val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
} else { } else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val)); cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
} }
@ -564,21 +564,21 @@ bool cosmoV_execute(CState *state) {
CValue ident = constants[indx]; // grabs identifier CValue ident = constants[indx]; // grabs identifier
// sanity check // sanity check
if (temp->type != COSMO_TOBJ || temp->val.obj->type != COBJ_OBJECT) { if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_OBJECT) {
cosmoV_error(state, "Couldn't set a field on non-object type %s!", cosmoV_typeStr(*temp)); cosmoV_error(state, "Couldn't set a field on non-object type %s!", cosmoV_typeStr(*temp));
break; break;
} }
CObjObject *object = (CObjObject*)temp->val.obj; CObjObject *object = (CObjObject*)cosmoV_readObj(*temp);
CValue *val = cosmoT_insert(state, &object->tbl, ident); CValue *val = cosmoT_insert(state, &object->tbl, ident);
// pop the object off the stack // pop the object off the stack
cosmoV_pop(state); cosmoV_pop(state);
// check that it's a number value // check that it's a number value
if (val->type == COSMO_TNUMBER) { if (IS_NUMBER(*val)) {
cosmoV_pushValue(state, *val); // pushes old value onto the stack :) cosmoV_pushValue(state, *val); // pushes old value onto the stack :)
*val = cosmoV_newNumber(val->val.num + inc); *val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
} else { } else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val)); cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
} }