Cosmo/src/cobj.c

655 lines
21 KiB
C
Raw Normal View History

2020-10-28 05:16:30 +00:00
#include "cstate.h"
#include "ctable.h"
#include "cobj.h"
#include "cmem.h"
#include "cvm.h"
#include "clex.h"
2020-10-28 05:16:30 +00:00
#include <string.h>
// we don't actually hash the whole string :eyes:
uint32_t hashString(const char *str, size_t sz) {
uint32_t hash = sz;
size_t step = (sz>>5)+1;
2021-01-02 05:06:24 +00:00
for (size_t i = sz; i >= step; i-=step)
2020-10-28 05:16:30 +00:00
hash = ((hash << 5) + (hash>>2)) + str[i-1];
return hash;
}
2020-11-06 01:53:55 +00:00
CObj *cosmoO_allocateBase(CState *state, size_t sz, CObjType type) {
2020-10-28 05:16:30 +00:00
CObj* obj = (CObj*)cosmoM_xmalloc(state, sz);
obj->type = type;
obj->isMarked = false;
obj->proto = state->protoObjects[type];
2020-10-28 05:16:30 +00:00
obj->next = state->objects;
state->objects = obj;
obj->nextRoot = NULL;
2020-10-28 23:29:50 +00:00
#ifdef GC_DEBUG
printf("allocated %p with OBJ_TYPE %d\n", obj, type);
#endif
2020-10-28 05:16:30 +00:00
return obj;
}
2020-11-06 01:53:55 +00:00
void cosmoO_free(CState *state, CObj* obj) {
2020-10-28 05:16:30 +00:00
#ifdef GC_DEBUG
printf("freeing %p [", obj);
printObject(obj);
printf("]\n");
#endif
switch(obj->type) {
case COBJ_STRING: {
CObjString *objStr = (CObjString*)obj;
2020-11-17 09:10:55 +00:00
cosmoM_freearray(state, char, objStr->str, objStr->length + 1);
2020-10-28 05:16:30 +00:00
cosmoM_free(state, CObjString, objStr);
break;
}
2020-11-04 04:10:51 +00:00
case COBJ_OBJECT: {
CObjObject *objTbl = (CObjObject*)obj;
cosmoT_clearTable(state, &objTbl->tbl);
2020-11-04 04:10:51 +00:00
cosmoM_free(state, CObjObject, objTbl);
break;
}
case COBJ_TABLE: {
CObjTable *tbl = (CObjTable*)obj;
cosmoT_clearTable(state, &tbl->tbl);
cosmoM_free(state, CObjTable, tbl);
break;
}
2020-10-28 05:16:30 +00:00
case COBJ_UPVALUE: {
cosmoM_free(state, CObjUpval, obj);
break;
}
case COBJ_FUNCTION: {
CObjFunction *objFunc = (CObjFunction*)obj;
cleanChunk(state, &objFunc->chunk);
cosmoM_free(state, CObjFunction, objFunc);
break;
}
case COBJ_CFUNCTION: {
cosmoM_free(state, CObjCFunction, obj);
break;
}
case COBJ_METHOD: {
cosmoM_free(state, CObjMethod, obj); // we don't own the closure or the object so /shrug
break;
}
case COBJ_ERROR: {
CObjError *err = (CObjError*)obj;
cosmoM_freearray(state, CCallFrame, err->frames, err->frameCount);
cosmoM_free(state, CObjError, obj);
break;
}
2020-10-28 05:16:30 +00:00
case COBJ_CLOSURE: {
CObjClosure* closure = (CObjClosure*)obj;
cosmoM_freearray(state, CObjUpval*, closure->upvalues, closure->upvalueCount);
cosmoM_free(state, CObjClosure, closure);
break;
}
case COBJ_MAX: { /* stubbed, should never happen */ }
2020-10-28 05:16:30 +00:00
}
}
2020-11-06 01:53:55 +00:00
bool cosmoO_equal(CObj* obj1, CObj* obj2) {
2020-10-28 05:16:30 +00:00
if (obj1->type != obj2->type)
return false;
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;
}
2020-10-28 05:16:30 +00:00
default:
return false;
2020-10-28 05:16:30 +00:00
}
}
CObjObject *cosmoO_newObject(CState *state) {
CObjObject *obj = (CObjObject*)cosmoO_allocateBase(state, sizeof(CObjObject), COBJ_OBJECT);
obj->istringFlags = 0;
obj->userP = NULL; // reserved for C API
obj->userT = 0;
obj->isLocked = false;
cosmoV_pushObj(state, (CObj*)obj); // so our GC can keep track of it
cosmoT_initTable(state, &obj->tbl, ARRAY_START);
cosmoV_pop(state);
return obj;
}
CObjTable *cosmoO_newTable(CState *state) {
CObjTable *obj = (CObjTable*)cosmoO_allocateBase(state, sizeof(CObjTable), COBJ_TABLE);
// init the table (might cause a GC event)
cosmoV_pushObj(state, (CObj*)obj); // so our GC can keep track of obj
cosmoT_initTable(state, &obj->tbl, ARRAY_START);
cosmoV_pop(state);
return obj;
}
2020-10-28 05:16:30 +00:00
CObjFunction *cosmoO_newFunction(CState *state) {
2020-11-06 01:53:55 +00:00
CObjFunction *func = (CObjFunction*)cosmoO_allocateBase(state, sizeof(CObjFunction), COBJ_FUNCTION);
2020-10-28 05:16:30 +00:00
func->args = 0;
func->upvals = 0;
func->variadic = false;
2020-10-28 05:16:30 +00:00
func->name = NULL;
2020-12-09 18:23:16 +00:00
func->module = NULL;
2020-10-28 05:16:30 +00:00
initChunk(state, &func->chunk, ARRAY_START);
return func;
}
CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func) {
2020-11-06 01:53:55 +00:00
CObjCFunction *cfunc = (CObjCFunction*)cosmoO_allocateBase(state, sizeof(CObjCFunction), COBJ_CFUNCTION);
2020-10-28 05:16:30 +00:00
cfunc->cfunc = func;
return cfunc;
}
CObjError *cosmoO_newError(CState *state, CValue err) {
CObjError *cerror = (CObjError*)cosmoO_allocateBase(state, sizeof(CObjError), COBJ_ERROR);
cerror->err = err;
cerror->frameCount = state->frameCount;
cerror->parserError = false;
// allocate the callframe
cerror->frames = cosmoM_xmalloc(state, sizeof(CCallFrame) * cerror->frameCount);
// clone the call frame
for (int i = 0; i < state->frameCount; i++)
cerror->frames[i] = state->callFrame[i];
return cerror;
}
CObjMethod *cosmoO_newMethod(CState *state, CValue func, CObj *obj) {
2020-11-13 05:04:09 +00:00
CObjMethod *method = (CObjMethod*)cosmoO_allocateBase(state, sizeof(CObjMethod), COBJ_METHOD);
method->func = func;
method->obj = obj;
return method;
}
2020-10-28 05:16:30 +00:00
CObjClosure *cosmoO_newClosure(CState *state, CObjFunction *func) {
2020-12-19 19:32:43 +00:00
// initialize array of pointers
2020-10-28 05:16:30 +00:00
CObjUpval **upvalues = cosmoM_xmalloc(state, sizeof(CObjUpval*) * func->upvals);
for (int i = 0; i < func->upvals; i++) {
upvalues[i] = NULL;
}
2020-11-06 01:53:55 +00:00
CObjClosure *closure = (CObjClosure*)cosmoO_allocateBase(state, sizeof(CObjClosure), COBJ_CLOSURE);
2020-10-28 05:16:30 +00:00
closure->function = func;
closure->upvalues = upvalues;
closure->upvalueCount = func->upvals;
return closure;
}
CObjUpval *cosmoO_newUpvalue(CState *state, CValue *val) {
2020-11-06 01:53:55 +00:00
CObjUpval *upval = (CObjUpval*)cosmoO_allocateBase(state, sizeof(CObjUpval), COBJ_UPVALUE);
2020-10-28 05:16:30 +00:00
upval->val = val;
upval->closed = cosmoV_newNil();
upval->next = NULL;
return upval;
}
CObjString *cosmoO_copyString(CState *state, const char *str, size_t length) {
uint32_t hash = hashString(str, length);
CObjString *lookup = cosmoT_lookupString(&state->strings, str, length, hash);
2020-10-28 05:16:30 +00:00
// have we already interned this string?
if (lookup != NULL)
return lookup;
char *buf = cosmoM_xmalloc(state, sizeof(char) * (length + 1)); // +1 for null terminator
memcpy(buf, str, length); // copy string to heap
buf[length] = '\0'; // don't forget our null terminator
2020-10-28 05:16:30 +00:00
return cosmoO_allocateString(state, buf, length, hash);
2020-10-28 05:16:30 +00:00
}
// length shouldn't include the null terminator! str should be a null terminated string! (char array should also have been allocated using cosmoM_xmalloc!)
CObjString *cosmoO_takeString(CState *state, char *str, size_t length) {
uint32_t hash = hashString(str, length);
2020-10-28 05:16:30 +00:00
CObjString *lookup = cosmoT_lookupString(&state->strings, str, length, hash);
2020-10-28 05:16:30 +00:00
// have we already interned this string?
if (lookup != NULL) {
cosmoM_freearray(state, char, str, length + 1); // free our passed character array, it's unneeded!
2020-10-28 05:16:30 +00:00
return lookup;
}
return cosmoO_allocateString(state, str, length, hash);
2020-10-28 05:16:30 +00:00
}
CObjString *cosmoO_allocateString(CState *state, const char *str, size_t sz, uint32_t hash) {
2020-11-06 01:53:55 +00:00
CObjString *strObj = (CObjString*)cosmoO_allocateBase(state, sizeof(CObjString), COBJ_STRING);
2020-12-10 02:46:20 +00:00
strObj->isIString = false;
2020-10-28 05:16:30 +00:00
strObj->str = (char*)str;
strObj->length = sz;
strObj->hash = hash;
// we push & pop the string so our GC can find it (we don't use freezeGC/unfreezeGC because we *want* a GC event to happen)
cosmoV_pushObj(state, (CObj*)strObj);
2020-10-28 05:16:30 +00:00
cosmoT_insert(state, &state->strings, cosmoV_newObj((CObj*)strObj));
cosmoV_pop(state);
return strObj;
}
CObjString *cosmoO_pushVFString(CState *state, const char *format, va_list args) {
StkPtr start = state->top;
const char *end;
char c;
int len;
while (true) {
end = strchr(format, '%'); // grab the next occurrence of '%'
len = -1; // -1 means no length specified
if (end == NULL) // the end, no '%' found
break;
// push the string before '%'
cosmoV_pushLString(state, format, (end - format));
reentry:
c = end[1]; // the character right after '%'
switch (c) {
case 'd': // int
cosmoV_pushNumber(state, va_arg(args, int));
break;
case 'f': // double
cosmoV_pushNumber(state, va_arg(args, double));
break;
case 's': // char *
if (len >= 0) // the length is specified
cosmoV_pushLString(state, va_arg(args, char *), len);
else
cosmoV_pushString(state, va_arg(args, char *));
break;
case '*': // length specifier
len = va_arg(args, int);
end++; // skip '*'
goto reentry;
default: {
char temp[2];
temp[0] = '%';
temp[1] = c;
cosmoV_pushLString(state, temp, 2);
}
}
format = end + 2; // + 2 because of % and the following character
}
cosmoV_pushString(state, format); // push the rest of the string
cosmoV_concat(state, state->top - start); // use cosmoV_concat to concat all the strings on the stack
return cosmoV_readString(*start); // start should be state->top - 1
}
// walks the protos of obj and checks for proto
bool cosmoO_isDescendant(CObj *obj, CObjObject *proto) {
CObjObject *curr = obj->proto;
while (curr != NULL) {
if (curr == proto)
return true; // found proto! return true
curr = ((CObj*)curr)->proto;
}
// we didn't find the proto
return false;
}
2021-01-13 00:27:29 +00:00
// 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)) {
cosmoV_pushValue(state, *val); // push function
cosmoV_pushObj(state, (CObj*)obj); // push object
if (cosmoV_call(state, 1, 1) != COSMOVM_OK) // call the function with the 1 argument
return false;
*val = *cosmoV_pop(state); // set value to the return value of __index
return true;
}
2021-01-13 00:27:29 +00:00
if (proto->_obj.proto != NULL && cosmoO_getRawObject(state, proto->_obj.proto, key, val, obj))
return true;
*val = cosmoV_newNil();
2021-01-13 00:27:29 +00:00
return true; // no protoobject to check against / key not found
}
return true;
2020-11-06 01:53:55 +00:00
}
2021-01-13 00:27:29 +00:00
void cosmoO_setRawObject(CState *state, CObjObject *proto, CValue key, CValue val, CObj *obj) {
2020-11-24 21:16:37 +00:00
CValue ret;
2020-12-06 20:11:33 +00:00
// if the object is locked, throw an error
if (proto->isLocked) {
cosmoV_error(state, "Couldn't set on a locked object!");
return;
}
// check for __setters
2021-01-13 00:27:29 +00:00
if (cosmoO_getIString(state, proto, ISTRING_SETTER, &ret) && IS_TABLE(ret) && cosmoT_get(&cosmoV_readTable(ret)->tbl, key, &ret)) {
cosmoV_pushValue(state, ret); // push function
cosmoV_pushObj(state, (CObj*)obj); // push object
cosmoV_pushValue(state, val); // push new value
cosmoV_call(state, 2, 0);
return;
2020-11-24 21:16:37 +00:00
}
2020-12-10 02:46:20 +00:00
// if the key is an IString, we need to reset the cache
if (IS_STRING(key) && cosmoV_readString(key)->isIString)
2021-01-13 00:27:29 +00:00
proto->istringFlags = 0; // reset cache
2020-12-10 02:46:20 +00:00
2020-11-24 21:16:37 +00:00
if (IS_NIL(val)) { // if we're setting an index to nil, we can safely mark that as a tombstone
2021-01-13 00:27:29 +00:00
cosmoT_remove(state, &proto->tbl, key);
2020-11-24 21:16:37 +00:00
} else {
2021-01-13 00:27:29 +00:00
CValue *newVal = cosmoT_insert(state, &proto->tbl, key);
2020-11-24 21:16:37 +00:00
*newVal = val;
}
2020-11-06 01:53:55 +00:00
}
void cosmoO_setUserP(CObjObject *object, void *p) {
object->userP = p;
}
void *cosmoO_getUserP(CObjObject *object) {
return object->userP;
}
void cosmoO_setUserI(CObjObject *object, int i) {
object->userI = i;
}
int cosmoO_getUserI(CObjObject *object) {
return object->userI;
}
void cosmoO_setUserT(CObjObject *object, int t) {
object->userT = t;
}
int cosmoO_getUserT(CObjObject *object) {
return object->userT;
}
void cosmoO_lock(CObjObject *object) {
object->isLocked = true;
}
void cosmoO_unlock(CObjObject *object) {
object->isLocked = false;
}
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_newObj(state->iStrings[flag]), val)) {
// mark it bad!
setFlagOn(object->istringFlags, flag);
return false;
}
return true; // :)
}
bool cosmoO_getIString(CState *state, CObjObject *object, int flag, CValue *val) {
CObjObject *obj = object;
do {
if (rawgetIString(state, obj, flag, val))
return true;
} while ((obj = obj->_obj.proto) != NULL); // sets obj to it's proto and compares it to NULL
return false; // obj->proto was false, the istring doesn't exist in this object chain
}
bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val) {
if (cosmoO_getIString(state, object, ISTRING_INDEX, val)) {
cosmoV_pushValue(state, *val); // push function
cosmoV_pushObj(state, (CObj*)object); // push object
cosmoV_pushValue(state, key); // push key
if (cosmoV_call(state, 2, 1) != COSMOVM_OK) // call the function with the 2 arguments
return false;
*val = *cosmoV_pop(state); // set value to the return value of __index
return true;
} else { // there's no __index function defined!
cosmoV_error(state, "Couldn't index object without __index function!");
}
return false;
}
bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val) {
CValue ret; // return value for cosmoO_getIString
if (cosmoO_getIString(state, object, ISTRING_NEWINDEX, &ret)) {
cosmoV_pushValue(state, ret); // push function
cosmoV_pushObj(state, (CObj*)object); // push object
cosmoV_pushValue(state, key); // push key & value pair
cosmoV_pushValue(state, val);
return cosmoV_call(state, 3, 0) == COSMOVM_OK;
} else { // there's no __newindex function defined
cosmoV_error(state, "Couldn't set index on object without __newindex function!");
}
return false;
}
CObjString *cosmoO_toString(CState *state, CObj *obj) {
CObjObject *protoObject = cosmoO_grabProto(obj);
CValue res;
// use user-defined __tostring
if (protoObject != NULL && cosmoO_getIString(state, protoObject, ISTRING_TOSTRING, &res)) {
cosmoV_pushValue(state, res);
cosmoV_pushObj(state, (CObj*)obj);
if (cosmoV_call(state, 1, 1) != COSMOVM_OK)
return cosmoO_copyString(state, "<err>", 5);
// make sure the __tostring function returned a string
StkPtr ret = cosmoV_getTop(state, 0);
if (!IS_STRING(*ret)) {
cosmoV_error(state, "__tostring expected to return <string>, got %s!", cosmoV_typeStr(*ret));
return cosmoO_copyString(state, "<err>", 5);
}
// return string
cosmoV_pop(state);
return (CObjString*)cosmoV_readRef(*ret);
}
switch (obj->type) {
2020-10-28 05:16:30 +00:00
case COBJ_STRING: {
return (CObjString*)obj;
2020-10-28 05:16:30 +00:00
}
case COBJ_CLOSURE: { // should be transparent to the user imo
CObjClosure *closure = (CObjClosure*)obj;
return cosmoO_toString(state, (CObj*)closure->function);
}
2020-10-28 05:16:30 +00:00
case COBJ_FUNCTION: {
CObjFunction *func = (CObjFunction*)obj;
2020-10-28 05:16:30 +00:00
return func->name != NULL ? func->name : cosmoO_copyString(state, UNNAMEDCHUNK, strlen(UNNAMEDCHUNK));
}
case COBJ_CFUNCTION: {
CObjCFunction *cfunc = (CObjCFunction*)obj;
char buf[64];
int sz = sprintf(buf, "<c function> %p", (void*)cfunc->cfunc) + 1; // +1 for the null character
return cosmoO_copyString(state, buf, sz);
}
case COBJ_OBJECT: {
char buf[64];
int sz = sprintf(buf, "<obj> %p", (void*)obj) + 1; // +1 for the null character
return cosmoO_copyString(state, buf, sz);
}
case COBJ_ERROR: {
CObjError *err = (CObjError*)obj;
return cosmoV_toString(state, err->err);
}
case COBJ_TABLE: {
char buf[64];
int sz = sprintf(buf, "<tbl> %p", (void*)obj) + 1; // +1 for the null character
return cosmoO_copyString(state, buf, sz);
}
default: {
char buf[64];
int sz = sprintf(buf, "<unkn obj> %p", (void*)obj) + 1; // +1 for the null character
return cosmoO_copyString(state, buf, sz);
}
2020-10-28 05:16:30 +00:00
}
}
cosmo_Number cosmoO_toNumber(CState *state, CObj *obj) {
2021-01-23 21:30:30 +00:00
CObjObject *proto = cosmoO_grabProto(obj);
CValue res;
if (proto != NULL && cosmoO_getIString(state, proto, ISTRING_TONUMBER, &res)) {
cosmoV_pushValue(state, res);
cosmoV_pushObj(state, (CObj*)obj);
2021-01-23 21:30:30 +00:00
if (cosmoV_call(state, 1, 1) != COSMOVM_OK) // call res, expect 1 return val of <number>
return 0;
StkPtr temp = cosmoV_getTop(state, 0);
if (!IS_NUMBER(*temp)) {
cosmoV_error(state, "__tonumber expected to return <number>, got %s!", cosmoV_typeStr(*temp));
return 0;
}
// return number
cosmoV_pop(state);
return cosmoV_readNumber(*temp);
}
switch (obj->type) {
case COBJ_STRING: {
CObjString *str = (CObjString*)obj;
return strtod(str->str, NULL);
}
default: // maybe in the future throw an error?
return 0;
}
}
2021-01-22 21:22:30 +00:00
int cosmoO_count(CState *state, CObj *obj) {
CObjObject *proto = cosmoO_grabProto(obj);
CValue res;
if (proto != NULL && cosmoO_getIString(state, proto, ISTRING_COUNT, &res)) {
cosmoV_pushValue(state, res);
cosmoV_pushObj(state, (CObj*)obj);
2021-01-23 21:30:30 +00:00
if (cosmoV_call(state, 1, 1) != COSMOVM_OK) // call res, we expect 1 return value of type <number>
2021-01-22 21:22:30 +00:00
return 0;
StkPtr ret = cosmoV_getTop(state, 0);
if (!IS_NUMBER(*ret)) {
cosmoV_error(state, "__count expected to return <number>, got %s!", cosmoV_typeStr(*ret));
return 0;
}
// return number
cosmoV_pop(state);
return (int)cosmoV_readNumber(*ret);
}
switch (obj->type) {
case COBJ_TABLE: { // returns the # of entries in the hash table
CObjTable *tbl = (CObjTable*)obj;
return cosmoT_count(&tbl->tbl);
}
case COBJ_STRING: { // returns the length of the string
CObjString *str = (CObjString*)obj;
return str->length;
}
default:
cosmoV_error(state, "Couldn't get # (count) of %s!", cosmoO_typeStr(obj));
return 0;
}
}
2020-10-28 05:16:30 +00:00
void printObject(CObj *o) {
switch (o->type) {
case COBJ_STRING: {
CObjString *objStr = (CObjString*)o;
printf("%.*s", objStr->length, objStr->str);
2020-10-28 05:16:30 +00:00
break;
}
2020-11-04 04:10:51 +00:00
case COBJ_OBJECT: {
2021-01-02 05:06:24 +00:00
printf("<obj> %p", (void*)o);
break;
}
case COBJ_TABLE: {
CObjTable *tbl = (CObjTable*)o;
printf("<tbl> %p", (void*)tbl);
break;
}
2020-10-28 05:16:30 +00:00
case COBJ_FUNCTION: {
CObjFunction *objFunc = (CObjFunction*)o;
if (objFunc->name != NULL)
printf("<function> %.*s", objFunc->name->length, objFunc->name->str);
else
printf("<function> %s", UNNAMEDCHUNK);
2020-10-28 05:16:30 +00:00
break;
}
case COBJ_CFUNCTION: {
CObjCFunction *objCFunc = (CObjCFunction*)o;
2021-01-02 05:06:24 +00:00
printf("<c function> %p", (void*)objCFunc->cfunc);
2020-10-28 05:16:30 +00:00
break;
}
case COBJ_ERROR: {
CObjError *err = (CObjError*)o;
printf("<error> %p -> ", (void*)o);
printValue(err->err);
break;
}
case COBJ_METHOD: {
CObjMethod *method = (CObjMethod*)o;
printf("<method> %p -> ", (void*)method);
2020-11-17 21:07:56 +00:00
printValue(method->func);
break;
}
case COBJ_CLOSURE: {
CObjClosure *closure = (CObjClosure*)o;
printf("<closure> %p -> ", (void*)closure);
printObject((CObj*)closure->function); // just print the function
break;
}
case COBJ_UPVALUE: {
CObjUpval *upval = (CObjUpval*)o;
printf("<upvalue> %p -> ", (void*)upval->val);
printValue(*upval->val);
break;
}
2020-10-28 05:16:30 +00:00
default:
2021-01-02 05:06:24 +00:00
printf("<unkn obj %p>", (void*)o);
2020-10-28 05:16:30 +00:00
}
}
const char *cosmoO_typeStr(CObj* obj) {
switch (obj->type) {
case COBJ_STRING: return "<string>";
case COBJ_OBJECT: return "<object>";
case COBJ_TABLE: return "<table>";
case COBJ_FUNCTION: return "<function>";
case COBJ_CFUNCTION: return "<c function>";
case COBJ_METHOD: return "<method>";
case COBJ_CLOSURE: return "<closure>";
case COBJ_UPVALUE: return "<upvalue>";
default:
return "<unkn obj>"; // TODO: maybe panic? could be a malformed object :eyes:
}
2021-01-02 05:06:24 +00:00
}