refactored cosmoV_set & cosmoV_get, renamed COSMO_TOBJ->COSMO_TREF

also changed print() to print raw primitives instead of generating a <string> needlessly. helped performance immensely in scripts like `examples/increment.cosmo`
This commit is contained in:
CPunch 2021-02-07 14:32:39 -06:00
parent 0d344f65df
commit 78e21a0f28
8 changed files with 92 additions and 38 deletions

View File

@ -10,8 +10,12 @@
int cosmoB_print(CState *state, int nargs, CValue *args) {
for (int i = 0; i < nargs; i++) {
CObjString *str = cosmoV_toString(state, args[i]);
printf("%s", cosmoO_readCString(str));
if (IS_REF(args[i])) { // if its a CObj*, generate the CObjString
CObjString *str = cosmoV_toString(state, args[i]);
printf("%s", cosmoO_readCString(str));
} else { // else, thats pretty expensive for primitives, just print the raw value
printValue(args[i]);
}
}
printf("\n");
@ -173,7 +177,7 @@ int cosmoB_oisChild(CState *state, int nargs, CValue *args) {
return 0;
}
if (!IS_OBJ(args[0]) || !IS_OBJECT(args[1])) {
if (!IS_REF(args[0]) || !IS_OBJECT(args[1])) {
cosmoV_typeError(state, "object.ischild()", "<reference obj>, <object>", "%s, %s", cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
return 0;
}

View File

@ -71,7 +71,7 @@ void tableRemoveWhite(CState *state, CTable *tbl) {
int cap = tbl->capacityMask + 1;
for (int i = 0; i < cap; i++) {
CTableEntry *entry = &tbl->table[i];
if (IS_OBJ(entry->key) && !(cosmoV_readRef(entry->key))->isMarked) { // if the key is a object and it's white (unmarked), remove it from the table
if (IS_REF(entry->key) && !(cosmoV_readRef(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);
}
}
@ -174,7 +174,7 @@ void markObject(CState *state, CObj *obj) {
}
void markValue(CState *state, CValue val) {
if (IS_OBJ(val))
if (IS_REF(val))
markObject(state, cosmoV_readRef(val));
}

View File

@ -130,7 +130,7 @@ typedef struct CObjUpval {
#define cosmoO_readCString(x) ((CObjString*)x)->str
static inline bool isObjType(CValue val, CObjType type) {
return IS_OBJ(val) && cosmoV_readRef(val)->type == type;
return IS_REF(val) && cosmoV_readRef(val)->type == type;
}
// just protects against macro expansion

View File

@ -66,7 +66,7 @@ uint32_t getObjectHash(CObj *obj) {
uint32_t getValueHash(CValue *val) {
switch (GET_TYPE(*val)) {
case COSMO_TOBJ:
case COSMO_TREF:
return getObjectHash(cosmoV_readRef(*val));
case COSMO_TNUMBER: {
uint32_t buf[sizeof(cosmo_Number)/sizeof(uint32_t)];

View File

@ -27,7 +27,7 @@ bool cosmoV_equal(CValue valA, CValue valB) {
switch (GET_TYPE(valA)) {
case COSMO_TBOOLEAN: return cosmoV_readBoolean(valA) == cosmoV_readBoolean(valB);
case COSMO_TNUMBER: return cosmoV_readNumber(valA) == cosmoV_readNumber(valB);
case COSMO_TOBJ: return cosmoO_equal(cosmoV_readRef(valA), cosmoV_readRef(valB));
case COSMO_TREF: return cosmoO_equal(cosmoV_readRef(valA), cosmoV_readRef(valB));
case COSMO_TNIL: return true;
default:
return false;
@ -44,7 +44,7 @@ CObjString *cosmoV_toString(CState *state, CValue val) {
case COSMO_TBOOLEAN: {
return cosmoV_readBoolean(val) ? cosmoO_copyString(state, "true", 4) : cosmoO_copyString(state, "false", 5);
}
case COSMO_TOBJ: {
case COSMO_TREF: {
return cosmoO_toString(state, cosmoV_readRef(val));
}
case COSMO_TNIL: {
@ -63,7 +63,7 @@ cosmo_Number cosmoV_toNumber(CState *state, CValue val) {
case COSMO_TBOOLEAN: {
return cosmoV_readBoolean(val) ? 1 : 0;
}
case COSMO_TOBJ: {
case COSMO_TREF: {
return cosmoO_toNumber(state, cosmoV_readRef(val));
}
case COSMO_TNIL: // fall through
@ -77,7 +77,7 @@ const char *cosmoV_typeStr(CValue val) {
case COSMO_TNIL: return "<nil>";
case COSMO_TBOOLEAN: return "<bool>";
case COSMO_TNUMBER: return "<number>";
case COSMO_TOBJ: return cosmoO_typeStr(cosmoV_readRef(val));
case COSMO_TREF: return cosmoO_typeStr(cosmoV_readRef(val));
default:
return "<unkn val>";
@ -92,7 +92,7 @@ void printValue(CValue val) {
case COSMO_TBOOLEAN:
printf(cosmoV_readBoolean(val) ? "true" : "false");
break;
case COSMO_TOBJ: {
case COSMO_TREF: {
printObject(cosmoV_readRef(val));
break;
}

View File

@ -6,7 +6,7 @@
typedef enum {
COSMO_TNUMBER, // number has to be 0 because NaN box
COSMO_TBOOLEAN,
COSMO_TOBJ,
COSMO_TREF,
COSMO_TNIL,
} CosmoType;
@ -47,7 +47,7 @@ typedef union CValue {
#define SIG_MASK (MASK_QUIETNAN | MASK_TYPE)
#define BOOL_SIG (MASK_QUIETNAN | ((uint64_t)(COSMO_TBOOLEAN) << 48))
#define OBJ_SIG (MASK_QUIETNAN | ((uint64_t)(COSMO_TOBJ) << 48))
#define OBJ_SIG (MASK_QUIETNAN | ((uint64_t)(COSMO_TREF) << 48))
#define NIL_SIG (MASK_QUIETNAN | ((uint64_t)(COSMO_TNIL) << 48))
#define cosmoV_newNumber(x) ((CValue){.num = x})
@ -62,7 +62,7 @@ typedef union CValue {
#define IS_NUMBER(x) (((x).data & MASK_QUIETNAN) != MASK_QUIETNAN)
#define IS_BOOLEAN(x) (((x).data & SIG_MASK) == BOOL_SIG)
#define IS_NIL(x) (((x).data & SIG_MASK) == NIL_SIG)
#define IS_OBJ(x) (((x).data & SIG_MASK) == OBJ_SIG)
#define IS_REF(x) (((x).data & SIG_MASK) == OBJ_SIG)
#else
/*
@ -83,7 +83,7 @@ typedef struct CValue {
#define cosmoV_newNumber(x) ((CValue){COSMO_TNUMBER, {.num = (x)}})
#define cosmoV_newBoolean(x) ((CValue){COSMO_TBOOLEAN, {.b = (x)}})
#define cosmoV_newRef(x) ((CValue){COSMO_TOBJ, {.obj = (CObj*)(x)}})
#define cosmoV_newRef(x) ((CValue){COSMO_TREF, {.obj = (CObj*)(x)}})
#define cosmoV_newNil() ((CValue){COSMO_TNIL, {.num = 0}})
// read CValues
@ -97,7 +97,7 @@ typedef struct CValue {
#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)
#define IS_REF(x) (GET_TYPE(x) == COSMO_TREF)
#endif

View File

@ -306,7 +306,7 @@ bool callCValue(CState *state, CValue func, int args, int nresults, int offset)
printf("(%d args)\n", args);
#endif
if (!IS_OBJ(func)) {
if (!IS_REF(func)) {
cosmoV_error(state, "Cannot call non-callable type %s!", cosmoV_typeStr(func));
return false;
}
@ -449,7 +449,7 @@ COSMO_API void cosmoV_makeTable(CState *state, int pairs) {
cosmoV_pushRef(state, (CObj*)newObj);
}
COSMO_API bool cosmoV_get(CState *state, CObj *_obj, CValue key, CValue *val) {
bool cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val) {
CObjObject *object = cosmoO_grabProto(_obj);
// no proto to get from
@ -472,7 +472,7 @@ COSMO_API bool cosmoV_get(CState *state, CObj *_obj, CValue key, CValue *val) {
return false;
}
COSMO_API bool cosmoV_set(CState *state, CObj *_obj, CValue key, CValue val) {
bool cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val) {
CObjObject *object = cosmoO_grabProto(_obj);
// no proto to set to
@ -486,8 +486,46 @@ COSMO_API bool cosmoV_set(CState *state, CObj *_obj, CValue key, CValue val) {
return true;
}
COSMO_API bool cosmoV_get(CState *state) {
CValue val;
StkPtr obj = cosmoV_getTop(state, 1); // object was pushed first
StkPtr key = cosmoV_getTop(state, 0); // then the key
if (!IS_REF(*obj)) {
cosmoV_error(state, "Couldn't get field from type %s!", cosmoV_typeStr(*obj));
return false;
}
if (!cosmoV_rawget(state, cosmoV_readRef(*obj), *key, &val))
return false;
// pop the obj & key, push the value
cosmoV_setTop(state, 2);
cosmoV_pushValue(state, val);
return true;
}
// yes, this would technically make it possible to set fields of types other than <string>. go crazy
COSMO_API bool cosmoV_set(CState *state) {
StkPtr obj = cosmoV_getTop(state, 2); // object was pushed first
StkPtr key = cosmoV_getTop(state, 1); // then the key
StkPtr val = cosmoV_getTop(state, 0); // and finally the value
if (!IS_REF(*obj)) {
cosmoV_error(state, "Couldn't set field on type %s!", cosmoV_typeStr(*obj));
return false;
}
if (!cosmoV_rawset(state, cosmoV_readRef(*obj), *key, *val))
return false;
// pop the obj, key & value
cosmoV_setTop(state, 3);
return true;
}
COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val) {
if (!cosmoV_get(state, obj, key, val))
if (!cosmoV_rawget(state, obj, key, val))
return false;
// if the result is callable, wrap it in an method
@ -701,7 +739,7 @@ int cosmoV_execute(CState *state) {
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the table
// sanity check
if (!IS_OBJ(*temp)) {
if (!IS_REF(*temp)) {
cosmoV_error(state, "Couldn't index type %s!", cosmoV_typeStr(*temp));
return -1;
}
@ -733,7 +771,7 @@ int cosmoV_execute(CState *state) {
StkPtr temp = cosmoV_getTop(state, 2); // table is after the key
// sanity check
if (!IS_OBJ(*temp)) {
if (!IS_REF(*temp)) {
cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp));
return -1;
}
@ -769,8 +807,8 @@ int cosmoV_execute(CState *state) {
uint16_t ident = READUINT(); // use for the key
// sanity check
if (IS_OBJ(*temp)) {
if (!cosmoV_set(state, cosmoV_readRef(*temp), constants[ident], *value))
if (IS_REF(*temp)) {
if (!cosmoV_rawset(state, cosmoV_readRef(*temp), constants[ident], *value))
return -1;
} else {
CObjString *field = cosmoV_toString(state, constants[ident]);
@ -788,8 +826,8 @@ int cosmoV_execute(CState *state) {
uint16_t ident = READUINT(); // use for the key
// sanity check
if (IS_OBJ(*temp)) {
if (!cosmoV_get(state, cosmoV_readRef(*temp), constants[ident], &val))
if (IS_REF(*temp)) {
if (!cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val))
return -1;
} else {
CObjString *field = cosmoV_toString(state, constants[ident]);
@ -807,7 +845,7 @@ int cosmoV_execute(CState *state) {
uint16_t ident = READUINT(); // use for the key
// this is almost identical to GETOBJECT, however cosmoV_getMethod is used instead of just cosmoV_get
if (IS_OBJ(*temp)) {
if (IS_REF(*temp)) {
if (!cosmoV_getMethod(state, cosmoV_readRef(*temp), constants[ident], &val))
return -1;
} else {
@ -828,9 +866,9 @@ int cosmoV_execute(CState *state) {
CValue val; // to hold our value
// sanity check
if (IS_OBJ(*temp)) {
if (IS_REF(*temp)) {
// get the field from the object
if (!cosmoV_get(state, cosmoV_readRef(*temp), constants[ident], &val))
if (!cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val))
return -1;
// now invoke the method!
@ -845,7 +883,7 @@ int cosmoV_execute(CState *state) {
case OP_ITER: {
StkPtr temp = cosmoV_getTop(state, 0); // should be the object/table
if (!IS_OBJ(*temp)) {
if (!IS_REF(*temp)) {
cosmoV_error(state, "Couldn't iterate over non-iterator type %s!", cosmoV_typeStr(*temp));
return -1;
}
@ -968,7 +1006,7 @@ int cosmoV_execute(CState *state) {
case OP_COUNT: {
StkPtr temp = cosmoV_getTop(state, 0);
if (!IS_OBJ(*temp)) {
if (!IS_REF(*temp)) {
cosmoV_error(state, "Expected non-primitive, got %s!", cosmoV_typeStr(*temp));
return -1;
}
@ -1038,7 +1076,7 @@ int cosmoV_execute(CState *state) {
StkPtr temp = cosmoV_getTop(state, 1); // object should be above the key
StkPtr key = cosmoV_getTop(state, 0); // grabs key
if (!IS_OBJ(*temp)) {
if (!IS_REF(*temp)) {
cosmoV_error(state, "Couldn't index non-indexable type %s!", cosmoV_typeStr(*temp));
return -1;
}
@ -1089,11 +1127,11 @@ int cosmoV_execute(CState *state) {
CValue ident = constants[indx]; // grabs identifier
// sanity check
if (IS_OBJ(*temp)) {
if (IS_REF(*temp)) {
CObj *obj = cosmoV_readRef(*temp);
CValue val;
if (!cosmoV_get(state, obj, ident, &val))
if (!cosmoV_rawget(state, obj, ident, &val))
return -1;
// pop the object off the stack
@ -1102,7 +1140,7 @@ int cosmoV_execute(CState *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)))
if (!cosmoV_rawset(state, obj, ident, cosmoV_newNumber(cosmoV_readNumber(val) + inc)))
return -1;
} else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));

View File

@ -40,8 +40,20 @@ COSMO_API bool cosmoV_registerProtoObject(CState *state, CObjType objType, CObjO
*/
COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *name);
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);
/*
expects object to be pushed, then the key.
if returns false an error was thrown, if returns true the value was pushed onto the stack and the object and key were popped
*/
COSMO_API bool cosmoV_get(CState *state);
/*
expects object to be pushed, then the key, and finally the new value.
if returns false an error was thrown, if returns true the value was set and the object key, and value were popped
*/
COSMO_API bool cosmoV_set(CState *state);
// wraps the closure into a CObjMethod, so the function is called as an invoked method
COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val);