mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-11-22 15:30:06 +00:00
Refactored cosmoO_equals
This sets up room for the '__equal' metamethod to be added - cosmoO_equals now requires the state to be passed - cosmoV_equals now requires the state to be passed - cosmoT_get now requires the state to be passed
This commit is contained in:
parent
afac75753f
commit
66d77bc54b
@ -32,21 +32,14 @@ int cosmoB_assert(CState *state, int nargs, CValue *args) {
|
||||
if (!IS_BOOLEAN(args[0]) || (nargs == 2 && !IS_STRING(args[1]))) {
|
||||
if (nargs == 2) {
|
||||
cosmoV_typeError(state, "assert()", "<boolean>, <string>", "%s, %s", cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
cosmoV_typeError(state, "assert()", "<boolean>", "%s", cosmoV_typeStr(args[0]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cosmoV_readBoolean(args[0])) { // expression passed was false, error!
|
||||
if (nargs == 2) {
|
||||
cosmoV_error(state, "%s", cosmoV_readCString(args[1]));
|
||||
}
|
||||
else { // optional custom error message
|
||||
cosmoV_error(state, "%s", "assert() failed!");
|
||||
}
|
||||
} // else do nothing :)
|
||||
if (!cosmoV_readBoolean(args[0])) // expression passed was false, error!
|
||||
cosmoV_error(state, "%s", nargs == 2 ? cosmoV_readCString(args[1]) : "assert() failed!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ void freeChunk(CState* state, CChunk *chunk) {
|
||||
int addConstant(CState* state, CChunk *chunk, CValue value) {
|
||||
// before adding the constant, check if we already have it
|
||||
for (size_t i = 0; i < chunk->constants.count; i++) {
|
||||
if (cosmoV_equal(value, chunk->constants.values[i]))
|
||||
if (cosmoV_equal(state, value, chunk->constants.values[i]))
|
||||
return i; // we already have a matching constant!
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,7 @@ void markArray(CState *state, CValueArray *array) {
|
||||
}
|
||||
|
||||
// mark all references associated with the object
|
||||
// black = keep, white = discard
|
||||
void blackenObject(CState *state, CObj *obj) {
|
||||
markObject(state, (CObj*)obj->proto);
|
||||
switch (obj->type) {
|
||||
|
45
src/cobj.c
45
src/cobj.c
@ -90,25 +90,48 @@ void cosmoO_free(CState *state, CObj* obj) {
|
||||
cosmoM_free(state, CObjClosure, closure);
|
||||
break;
|
||||
}
|
||||
case COBJ_MAX: { /* stubbed, should never happen */ }
|
||||
case COBJ_MAX:
|
||||
default: { /* stubbed, should never happen */ }
|
||||
}
|
||||
}
|
||||
|
||||
bool cosmoO_equal(CObj* obj1, CObj* obj2) {
|
||||
bool cosmoO_equal(CState *state, CObj* obj1, CObj* obj2) {
|
||||
if (obj1 == obj2) // its the same object, this compares strings for us since they're interned anyways :)
|
||||
return true;
|
||||
|
||||
if (obj1->type != obj2->type)
|
||||
return false;
|
||||
goto _eqFail;
|
||||
|
||||
switch (obj1->type) {
|
||||
case COBJ_STRING:
|
||||
return obj1 == obj2; // compare pointers because we already intern all strings :)
|
||||
case COBJ_CFUNCTION: {
|
||||
CObjCFunction *cfunc1 = (CObjCFunction*)obj1;
|
||||
CObjCFunction *cfunc2 = (CObjCFunction*)obj2;
|
||||
return cfunc1->cfunc == cfunc2->cfunc;
|
||||
if (cfunc1->cfunc == cfunc2->cfunc)
|
||||
return true;
|
||||
goto _eqFail;
|
||||
}
|
||||
case COBJ_METHOD: {
|
||||
CObjMethod *method1 = (CObjMethod*)obj1;
|
||||
CObjMethod *method2 = (CObjMethod*)obj2;
|
||||
if (cosmoV_equal(state, method1->func, method2->func))
|
||||
return true;
|
||||
goto _eqFail;
|
||||
}
|
||||
case COBJ_CLOSURE: {
|
||||
CObjClosure *closure1 = (CObjClosure*)obj1;
|
||||
CObjClosure *closure2 = (CObjClosure*)obj2;
|
||||
// we just compare the function pointer
|
||||
if (closure1->function == closure2->function)
|
||||
return true;
|
||||
goto _eqFail;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
goto _eqFail;
|
||||
}
|
||||
|
||||
_eqFail:
|
||||
// TODO: add support for an '__equal' metamethod
|
||||
return false;
|
||||
}
|
||||
|
||||
CObjObject *cosmoO_newObject(CState *state) {
|
||||
@ -312,8 +335,8 @@ bool cosmoO_isDescendant(CObj *obj, CObjObject *proto) {
|
||||
|
||||
// returns false if error thrown
|
||||
bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj) {
|
||||
if (!cosmoT_get(&proto->tbl, key, val)) { // if the field doesn't exist in the object, check the proto
|
||||
if (cosmoO_getIString(state, proto, ISTRING_GETTER, val) && IS_TABLE(*val) && cosmoT_get(&cosmoV_readTable(*val)->tbl, key, val)) {
|
||||
if (!cosmoT_get(state, &proto->tbl, key, val)) { // if the field doesn't exist in the object, check the proto
|
||||
if (cosmoO_getIString(state, proto, ISTRING_GETTER, val) && IS_TABLE(*val) && cosmoT_get(state, &cosmoV_readTable(*val)->tbl, key, val)) {
|
||||
cosmoV_pushValue(state, *val); // push function
|
||||
cosmoV_pushRef(state, (CObj*)obj); // push object
|
||||
if (cosmoV_call(state, 1, 1) != COSMOVM_OK) // call the function with the 1 argument
|
||||
@ -342,7 +365,7 @@ void cosmoO_setRawObject(CState *state, CObjObject *proto, CValue key, CValue va
|
||||
}
|
||||
|
||||
// check for __setters
|
||||
if (cosmoO_getIString(state, proto, ISTRING_SETTER, &ret) && IS_TABLE(ret) && cosmoT_get(&cosmoV_readTable(ret)->tbl, key, &ret)) {
|
||||
if (cosmoO_getIString(state, proto, ISTRING_SETTER, &ret) && IS_TABLE(ret) && cosmoT_get(state, &cosmoV_readTable(ret)->tbl, key, &ret)) {
|
||||
cosmoV_pushValue(state, ret); // push function
|
||||
cosmoV_pushRef(state, (CObj*)obj); // push object
|
||||
cosmoV_pushValue(state, val); // push new value
|
||||
@ -398,7 +421,7 @@ bool rawgetIString(CState *state, CObjObject *object, int flag, CValue *val) {
|
||||
if (readFlag(object->istringFlags, flag))
|
||||
return false; // it's been cached as bad
|
||||
|
||||
if (!cosmoT_get(&object->tbl, cosmoV_newRef(state->iStrings[flag]), val)) {
|
||||
if (!cosmoT_get(state, &object->tbl, cosmoV_newRef(state->iStrings[flag]), val)) {
|
||||
// mark it bad!
|
||||
setFlagOn(object->istringFlags, flag);
|
||||
return false;
|
||||
|
@ -136,7 +136,7 @@ static inline bool IS_CALLABLE(CValue val) {
|
||||
}
|
||||
|
||||
void cosmoO_free(CState *state, CObj* obj);
|
||||
bool cosmoO_equal(CObj* obj1, CObj* obj2);
|
||||
bool cosmoO_equal(CState *state, CObj* obj1, CObj* obj2);
|
||||
|
||||
// walks the protos of obj and checks for proto
|
||||
bool cosmoO_isDescendant(CObj *obj, CObjObject *proto);
|
||||
|
14
src/ctable.c
14
src/ctable.c
@ -86,7 +86,7 @@ uint32_t getValueHash(CValue *val) {
|
||||
}
|
||||
|
||||
// mask should always be (capacity - 1)
|
||||
static CTableEntry *findEntry(CTableEntry *entries, int mask, CValue key) {
|
||||
static CTableEntry *findEntry(CState *state, CTableEntry *entries, int mask, CValue key) {
|
||||
uint32_t hash = getValueHash(&key);
|
||||
uint32_t indx = hash & mask; // since we know the capacity will *always* be a power of 2, we can use bitwise & to perform a MUCH faster mod operation
|
||||
CTableEntry *tomb = NULL;
|
||||
@ -104,7 +104,7 @@ static CTableEntry *findEntry(CTableEntry *entries, int mask, CValue key) {
|
||||
// its a tombstone!
|
||||
tomb = entry;
|
||||
}
|
||||
} else if (cosmoV_equal(entry->key, key)) {
|
||||
} else if (cosmoV_equal(state, entry->key, key)) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -142,7 +142,7 @@ static void resizeTbl(CState *state, CTable *tbl, int newCapacity, bool canShrin
|
||||
continue; // skip empty keys
|
||||
|
||||
// get new entry location & update the node
|
||||
CTableEntry *newEntry = findEntry(entries, newCapacity - 1, oldEntry->key);
|
||||
CTableEntry *newEntry = findEntry(state, entries, newCapacity - 1, oldEntry->key);
|
||||
newEntry->key = oldEntry->key;
|
||||
newEntry->val = oldEntry->val;
|
||||
newCount++; // inc count
|
||||
@ -178,7 +178,7 @@ COSMO_API CValue* cosmoT_insert(CState *state, CTable *tbl, CValue key) {
|
||||
}
|
||||
|
||||
// insert into the table
|
||||
CTableEntry *entry = findEntry(tbl->table, tbl->capacityMask, key); // -1 for our capacity mask
|
||||
CTableEntry *entry = findEntry(state, tbl->table, tbl->capacityMask, key); // -1 for our capacity mask
|
||||
|
||||
if (IS_NIL(entry->key)) {
|
||||
if (IS_NIL(entry->val)) // is it empty?
|
||||
@ -191,14 +191,14 @@ COSMO_API CValue* cosmoT_insert(CState *state, CTable *tbl, CValue key) {
|
||||
return &entry->val;
|
||||
}
|
||||
|
||||
bool cosmoT_get(CTable *tbl, CValue key, CValue *val) {
|
||||
bool cosmoT_get(CState *state, CTable *tbl, CValue key, CValue *val) {
|
||||
// sanity check
|
||||
if (tbl->count == 0) {
|
||||
*val = cosmoV_newNil();
|
||||
return false;
|
||||
}
|
||||
|
||||
CTableEntry *entry = findEntry(tbl->table, tbl->capacityMask, key);
|
||||
CTableEntry *entry = findEntry(state, tbl->table, tbl->capacityMask, key);
|
||||
*val = entry->val;
|
||||
|
||||
// return if get was successful
|
||||
@ -208,7 +208,7 @@ bool cosmoT_get(CTable *tbl, CValue key, CValue *val) {
|
||||
bool cosmoT_remove(CState* state, CTable *tbl, CValue key) {
|
||||
if (tbl->count == 0) return 0; // sanity check
|
||||
|
||||
CTableEntry *entry = findEntry(tbl->table, tbl->capacityMask, key);
|
||||
CTableEntry *entry = findEntry(state, tbl->table, tbl->capacityMask, key);
|
||||
if (IS_NIL(entry->key)) // sanity check
|
||||
return false;
|
||||
|
||||
|
@ -26,7 +26,7 @@ bool cosmoT_checkShrink(CState *state, CTable *tbl);
|
||||
|
||||
CObjString *cosmoT_lookupString(CTable *tbl, const char *str, int length, uint32_t hash);
|
||||
CValue *cosmoT_insert(CState *state, CTable *tbl, CValue key);
|
||||
bool cosmoT_get(CTable *tbl, CValue key, CValue *val);
|
||||
bool cosmoT_get(CState *state, CTable *tbl, CValue key, CValue *val);
|
||||
bool cosmoT_remove(CState *state, CTable *tbl, CValue key);
|
||||
|
||||
void cosmoT_printTable(CTable *tbl, const char *name);
|
||||
|
@ -19,7 +19,7 @@ void appendValArray(CState *state, CValueArray *array, CValue val) {
|
||||
array->values[array->count++] = val;
|
||||
}
|
||||
|
||||
bool cosmoV_equal(CValue valA, CValue valB) {
|
||||
bool cosmoV_equal(CState *state, CValue valA, CValue valB) {
|
||||
if (GET_TYPE(valA) != GET_TYPE(valB)) // are they the same type?
|
||||
return false;
|
||||
|
||||
@ -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_TREF: return cosmoO_equal(cosmoV_readRef(valA), cosmoV_readRef(valB));
|
||||
case COSMO_TREF: return cosmoO_equal(state, cosmoV_readRef(valA), cosmoV_readRef(valB));
|
||||
case COSMO_TNIL: return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -114,7 +114,7 @@ void cleanValArray(CState *state, CValueArray *array); // cleans array
|
||||
void appendValArray(CState *state, CValueArray *array, CValue val);
|
||||
|
||||
void printValue(CValue val);
|
||||
COSMO_API bool cosmoV_equal(CValue valA, CValue valB);
|
||||
COSMO_API bool cosmoV_equal(CState *state, CValue valA, CValue valB);
|
||||
COSMO_API CObjString *cosmoV_toString(CState *state, CValue val);
|
||||
COSMO_API cosmo_Number cosmoV_toNumber(CState *state, CValue val);
|
||||
COSMO_API const char *cosmoV_typeStr(CValue val); // return constant char array for corresponding type
|
||||
|
@ -633,7 +633,7 @@ int cosmoV_execute(CState *state) {
|
||||
uint16_t indx = READUINT();
|
||||
CValue ident = constants[indx]; // grabs identifier
|
||||
CValue val; // to hold our value
|
||||
cosmoT_get(&state->globals->tbl, ident, &val);
|
||||
cosmoT_get(state, &state->globals->tbl, ident, &val);
|
||||
cosmoV_pushValue(state, val); // pushes the value to the stack
|
||||
continue;
|
||||
}
|
||||
@ -766,7 +766,7 @@ int cosmoV_execute(CState *state) {
|
||||
} else if (obj->type == COBJ_TABLE) {
|
||||
CObjTable *tbl = (CObjTable*)obj;
|
||||
|
||||
cosmoT_get(&tbl->tbl, *key, &val);
|
||||
cosmoT_get(state, &tbl->tbl, *key, &val);
|
||||
} else {
|
||||
cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp));
|
||||
return -1;
|
||||
@ -1182,7 +1182,7 @@ int cosmoV_execute(CState *state) {
|
||||
StkPtr valA = cosmoV_pop(state);
|
||||
|
||||
// compare & push
|
||||
cosmoV_pushBoolean(state, cosmoV_equal(*valA, *valB));
|
||||
cosmoV_pushBoolean(state, cosmoV_equal(state, *valA, *valB));
|
||||
continue;
|
||||
}
|
||||
case OP_GREATER: {
|
||||
|
@ -62,6 +62,10 @@ 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);
|
||||
|
||||
// clears the stack, callstack and restores the state into a usable state after a calloverflow or another hard to recover error
|
||||
// (keeps the global table intact)
|
||||
COSMO_API bool cosmoV_restore(CState *state);
|
||||
|
||||
// nice to have wrappers
|
||||
|
||||
// pushes a raw CValue to the stack, might throw an error if the stack is overflowed (with the SAFE_STACK macro on)
|
||||
|
Loading…
Reference in New Issue
Block a user