mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-11-24 16:11:04 +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
40739e9bea
commit
3890c9dd1e
@ -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 (!IS_BOOLEAN(args[0]) || (nargs == 2 && !IS_STRING(args[1]))) {
|
||||||
if (nargs == 2) {
|
if (nargs == 2) {
|
||||||
cosmoV_typeError(state, "assert()", "<boolean>, <string>", "%s, %s", cosmoV_typeStr(args[0]), cosmoV_typeStr(args[1]));
|
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]));
|
cosmoV_typeError(state, "assert()", "<boolean>", "%s", cosmoV_typeStr(args[0]));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cosmoV_readBoolean(args[0])) { // expression passed was false, error!
|
if (!cosmoV_readBoolean(args[0])) // expression passed was false, error!
|
||||||
if (nargs == 2) {
|
cosmoV_error(state, "%s", nargs == 2 ? cosmoV_readCString(args[1]) : "assert() failed!");
|
||||||
cosmoV_error(state, "%s", cosmoV_readCString(args[1]));
|
|
||||||
}
|
|
||||||
else { // optional custom error message
|
|
||||||
cosmoV_error(state, "%s", "assert() failed!");
|
|
||||||
}
|
|
||||||
} // else do nothing :)
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ void freeChunk(CState* state, CChunk *chunk) {
|
|||||||
int addConstant(CState* state, CChunk *chunk, CValue value) {
|
int addConstant(CState* state, CChunk *chunk, CValue value) {
|
||||||
// before adding the constant, check if we already have it
|
// before adding the constant, check if we already have it
|
||||||
for (size_t i = 0; i < chunk->constants.count; i++) {
|
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!
|
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
|
// mark all references associated with the object
|
||||||
|
// black = keep, white = discard
|
||||||
void blackenObject(CState *state, CObj *obj) {
|
void blackenObject(CState *state, CObj *obj) {
|
||||||
markObject(state, (CObj*)obj->proto);
|
markObject(state, (CObj*)obj->proto);
|
||||||
switch (obj->type) {
|
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);
|
cosmoM_free(state, CObjClosure, closure);
|
||||||
break;
|
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)
|
if (obj1->type != obj2->type)
|
||||||
return false;
|
goto _eqFail;
|
||||||
|
|
||||||
switch (obj1->type) {
|
switch (obj1->type) {
|
||||||
case COBJ_STRING:
|
|
||||||
return obj1 == obj2; // compare pointers because we already intern all strings :)
|
|
||||||
case COBJ_CFUNCTION: {
|
case COBJ_CFUNCTION: {
|
||||||
CObjCFunction *cfunc1 = (CObjCFunction*)obj1;
|
CObjCFunction *cfunc1 = (CObjCFunction*)obj1;
|
||||||
CObjCFunction *cfunc2 = (CObjCFunction*)obj2;
|
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:
|
default:
|
||||||
return false;
|
goto _eqFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_eqFail:
|
||||||
|
// TODO: add support for an '__equal' metamethod
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjObject *cosmoO_newObject(CState *state) {
|
CObjObject *cosmoO_newObject(CState *state) {
|
||||||
@ -312,8 +335,8 @@ bool cosmoO_isDescendant(CObj *obj, CObjObject *proto) {
|
|||||||
|
|
||||||
// returns false if error thrown
|
// returns false if error thrown
|
||||||
bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj) {
|
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 (!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(&cosmoV_readTable(*val)->tbl, key, val)) {
|
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_pushValue(state, *val); // push function
|
||||||
cosmoV_pushRef(state, (CObj*)obj); // push object
|
cosmoV_pushRef(state, (CObj*)obj); // push object
|
||||||
if (cosmoV_call(state, 1, 1) != COSMOVM_OK) // call the function with the 1 argument
|
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
|
// 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_pushValue(state, ret); // push function
|
||||||
cosmoV_pushRef(state, (CObj*)obj); // push object
|
cosmoV_pushRef(state, (CObj*)obj); // push object
|
||||||
cosmoV_pushValue(state, val); // push new value
|
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))
|
if (readFlag(object->istringFlags, flag))
|
||||||
return false; // it's been cached as bad
|
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!
|
// mark it bad!
|
||||||
setFlagOn(object->istringFlags, flag);
|
setFlagOn(object->istringFlags, flag);
|
||||||
return false;
|
return false;
|
||||||
|
@ -136,7 +136,7 @@ static inline bool IS_CALLABLE(CValue val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cosmoO_free(CState *state, CObj* obj);
|
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
|
// walks the protos of obj and checks for proto
|
||||||
bool cosmoO_isDescendant(CObj *obj, CObjObject *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)
|
// 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 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
|
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;
|
CTableEntry *tomb = NULL;
|
||||||
@ -104,7 +104,7 @@ static CTableEntry *findEntry(CTableEntry *entries, int mask, CValue key) {
|
|||||||
// its a tombstone!
|
// its a tombstone!
|
||||||
tomb = entry;
|
tomb = entry;
|
||||||
}
|
}
|
||||||
} else if (cosmoV_equal(entry->key, key)) {
|
} else if (cosmoV_equal(state, entry->key, key)) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ static void resizeTbl(CState *state, CTable *tbl, int newCapacity, bool canShrin
|
|||||||
continue; // skip empty keys
|
continue; // skip empty keys
|
||||||
|
|
||||||
// get new entry location & update the node
|
// 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->key = oldEntry->key;
|
||||||
newEntry->val = oldEntry->val;
|
newEntry->val = oldEntry->val;
|
||||||
newCount++; // inc count
|
newCount++; // inc count
|
||||||
@ -178,7 +178,7 @@ COSMO_API CValue* cosmoT_insert(CState *state, CTable *tbl, CValue key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// insert into the table
|
// 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->key)) {
|
||||||
if (IS_NIL(entry->val)) // is it empty?
|
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;
|
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
|
// sanity check
|
||||||
if (tbl->count == 0) {
|
if (tbl->count == 0) {
|
||||||
*val = cosmoV_newNil();
|
*val = cosmoV_newNil();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CTableEntry *entry = findEntry(tbl->table, tbl->capacityMask, key);
|
CTableEntry *entry = findEntry(state, tbl->table, tbl->capacityMask, key);
|
||||||
*val = entry->val;
|
*val = entry->val;
|
||||||
|
|
||||||
// return if get was successful
|
// 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) {
|
bool cosmoT_remove(CState* state, CTable *tbl, CValue key) {
|
||||||
if (tbl->count == 0) return 0; // sanity check
|
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
|
if (IS_NIL(entry->key)) // sanity check
|
||||||
return false;
|
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);
|
CObjString *cosmoT_lookupString(CTable *tbl, const char *str, int length, uint32_t hash);
|
||||||
CValue *cosmoT_insert(CState *state, CTable *tbl, CValue key);
|
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);
|
bool cosmoT_remove(CState *state, CTable *tbl, CValue key);
|
||||||
|
|
||||||
void cosmoT_printTable(CTable *tbl, const char *name);
|
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;
|
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?
|
if (GET_TYPE(valA) != GET_TYPE(valB)) // are they the same type?
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ bool cosmoV_equal(CValue valA, CValue valB) {
|
|||||||
switch (GET_TYPE(valA)) {
|
switch (GET_TYPE(valA)) {
|
||||||
case COSMO_TBOOLEAN: return cosmoV_readBoolean(valA) == cosmoV_readBoolean(valB);
|
case COSMO_TBOOLEAN: return cosmoV_readBoolean(valA) == cosmoV_readBoolean(valB);
|
||||||
case COSMO_TNUMBER: return cosmoV_readNumber(valA) == cosmoV_readNumber(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;
|
case COSMO_TNIL: return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -114,7 +114,7 @@ void cleanValArray(CState *state, CValueArray *array); // cleans array
|
|||||||
void appendValArray(CState *state, CValueArray *array, CValue val);
|
void appendValArray(CState *state, CValueArray *array, CValue val);
|
||||||
|
|
||||||
void printValue(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 CObjString *cosmoV_toString(CState *state, CValue val);
|
||||||
COSMO_API cosmo_Number cosmoV_toNumber(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
|
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();
|
uint16_t indx = READUINT();
|
||||||
CValue ident = constants[indx]; // grabs identifier
|
CValue ident = constants[indx]; // grabs identifier
|
||||||
CValue val; // to hold our value
|
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
|
cosmoV_pushValue(state, val); // pushes the value to the stack
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -766,7 +766,7 @@ int cosmoV_execute(CState *state) {
|
|||||||
} else if (obj->type == COBJ_TABLE) {
|
} else if (obj->type == COBJ_TABLE) {
|
||||||
CObjTable *tbl = (CObjTable*)obj;
|
CObjTable *tbl = (CObjTable*)obj;
|
||||||
|
|
||||||
cosmoT_get(&tbl->tbl, *key, &val);
|
cosmoT_get(state, &tbl->tbl, *key, &val);
|
||||||
} else {
|
} else {
|
||||||
cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp));
|
cosmoV_error(state, "No proto defined! Couldn't __index from type %s", cosmoV_typeStr(*temp));
|
||||||
return -1;
|
return -1;
|
||||||
@ -1182,7 +1182,7 @@ int cosmoV_execute(CState *state) {
|
|||||||
StkPtr valA = cosmoV_pop(state);
|
StkPtr valA = cosmoV_pop(state);
|
||||||
|
|
||||||
// compare & push
|
// compare & push
|
||||||
cosmoV_pushBoolean(state, cosmoV_equal(*valA, *valB));
|
cosmoV_pushBoolean(state, cosmoV_equal(state, *valA, *valB));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
case OP_GREATER: {
|
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
|
// 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);
|
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
|
// 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)
|
// 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