mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-11-05 08:10:05 +00:00
Minor table refactor, added cosmoV_compileString and loadstring() to baselib
cosmoV_compileString is recommended since it'll push the result (<error> or <closure>) onto the stack. also, fixed some GC-related bugs, so yay!
This commit is contained in:
parent
8dc8cef7dc
commit
c510c9aebf
@ -57,6 +57,24 @@ int cosmoB_pcall(CState *state, int nargs, CValue *args) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cosmoB_loadstring(CState *state, int nargs, CValue *args) {
|
||||||
|
if (nargs < 1) {
|
||||||
|
cosmoV_error(state, "loadstring() expected 1 argument, got %d!", nargs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_STRING(args[0])) {
|
||||||
|
cosmoV_typeError(state, "loadstring()", "<string>", "%s", cosmoV_typeStr(args[0]));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CObjString *str = cosmoV_readString(args[0]);
|
||||||
|
bool res = cosmoV_compileString(state, str->str, "");
|
||||||
|
|
||||||
|
cosmo_insert(state, 0, cosmoV_newBoolean(res));
|
||||||
|
return 2; // <boolean>, <closure> or <error>
|
||||||
|
}
|
||||||
|
|
||||||
// ================================================================ [STRING.*] ================================================================
|
// ================================================================ [STRING.*] ================================================================
|
||||||
|
|
||||||
// string.sub
|
// string.sub
|
||||||
@ -103,23 +121,32 @@ int cosmoB_sSub(CState *state, int nargs, CValue *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cosmoB_loadLibrary(CState *state) {
|
void cosmoB_loadLibrary(CState *state) {
|
||||||
// print
|
const char *identifiers[] = {
|
||||||
cosmoV_pushString(state, "print");
|
"print",
|
||||||
cosmoV_pushCFunction(state, cosmoB_print);
|
"assert",
|
||||||
|
"type",
|
||||||
|
"pcall",
|
||||||
|
"loadstring"
|
||||||
|
};
|
||||||
|
|
||||||
// assert (for unit testing)
|
CosmoCFunction baseLib[] = {
|
||||||
cosmoV_pushString(state, "assert");
|
cosmoB_print,
|
||||||
cosmoV_pushCFunction(state, cosmoB_assert);
|
cosmoB_assert,
|
||||||
|
cosmoB_type,
|
||||||
|
cosmoB_pcall,
|
||||||
|
cosmoB_loadstring
|
||||||
|
};
|
||||||
|
|
||||||
// type
|
int i;
|
||||||
cosmoV_pushString(state, "type");
|
for (i = 0; i < sizeof(identifiers)/sizeof(identifiers[0]); i++) {
|
||||||
cosmoV_pushCFunction(state, cosmoB_type);
|
cosmoV_pushString(state, identifiers[i]);
|
||||||
|
cosmoV_pushCFunction(state, baseLib[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// pcall
|
// register all the pushed c functions and the strings as globals
|
||||||
cosmoV_pushString(state, "pcall");
|
cosmoV_register(state, i);
|
||||||
cosmoV_pushCFunction(state, cosmoB_pcall);
|
|
||||||
|
|
||||||
// string.
|
// string.*
|
||||||
cosmoV_pushString(state, "string");
|
cosmoV_pushString(state, "string");
|
||||||
|
|
||||||
// sub
|
// sub
|
||||||
@ -127,19 +154,19 @@ void cosmoB_loadLibrary(CState *state) {
|
|||||||
cosmoV_pushCFunction(state, cosmoB_sSub);
|
cosmoV_pushCFunction(state, cosmoB_sSub);
|
||||||
|
|
||||||
cosmoV_makeTable(state, 1);
|
cosmoV_makeTable(state, 1);
|
||||||
// string.
|
// string.*
|
||||||
|
|
||||||
// register these all to the global table
|
// register "string" to that table
|
||||||
cosmoV_register(state, 5);
|
cosmoV_register(state, 1);
|
||||||
|
|
||||||
// make string object for CObjStrings
|
// make string object for CObjStrings
|
||||||
|
|
||||||
// sub
|
// sub
|
||||||
cosmoV_pushString(state, "sub");
|
cosmoV_pushString(state, "sub");
|
||||||
cosmoV_pushCFunction(state, cosmoB_sSub);
|
cosmoV_pushCFunction(state, cosmoB_sSub);
|
||||||
|
|
||||||
cosmoV_makeObject(state, 1);
|
cosmoV_makeObject(state, 1);
|
||||||
|
|
||||||
|
// grab the object from the stack and set the base protoObject
|
||||||
StkPtr obj = cosmoV_pop(state);
|
StkPtr obj = cosmoV_pop(state);
|
||||||
state->protoObjects[COBJ_STRING] = cosmoV_readObject(*obj);
|
state->protoObjects[COBJ_STRING] = cosmoV_readObject(*obj);
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,8 @@ void markTable(CState *state, CTable *tbl) {
|
|||||||
if (tbl->table == NULL) // table is still being initialized
|
if (tbl->table == NULL) // table is still being initialized
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < tbl->capacity; i++) {
|
int cap = tbl->capacityMask + 1;
|
||||||
|
for (int i = 0; i < cap; i++) {
|
||||||
CTableEntry *entry = &tbl->table[i];
|
CTableEntry *entry = &tbl->table[i];
|
||||||
markValue(state, entry->key);
|
markValue(state, entry->key);
|
||||||
markValue(state, entry->val);
|
markValue(state, entry->val);
|
||||||
@ -67,7 +68,8 @@ void tableRemoveWhite(CState *state, CTable *tbl) {
|
|||||||
if (tbl->table == NULL) // table is still being initialized
|
if (tbl->table == NULL) // table is still being initialized
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < tbl->capacity; i++) {
|
int cap = tbl->capacityMask + 1;
|
||||||
|
for (int i = 0; i < cap; i++) {
|
||||||
CTableEntry *entry = &tbl->table[i];
|
CTableEntry *entry = &tbl->table[i];
|
||||||
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
|
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);
|
||||||
|
@ -1587,20 +1587,19 @@ CObjFunction* cosmoP_compileString(CState *state, const char *source, const char
|
|||||||
endCompiler(&parser);
|
endCompiler(&parser);
|
||||||
freeParseState(&parser);
|
freeParseState(&parser);
|
||||||
|
|
||||||
// the VM still expects a result on the stack
|
|
||||||
cosmoV_pushValue(state, cosmoV_newNil());
|
|
||||||
cosmoM_unfreezeGC(state);
|
cosmoM_unfreezeGC(state);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
CObjFunction* resFunc = compiler.function;
|
CObjFunction* resFunc = compiler.function;
|
||||||
|
|
||||||
// VM expects the closure on the stack :P (we do this before ending the compiler so our GC doesn't free it)
|
|
||||||
cosmoV_pushValue(state, cosmoV_newObj((CObj*)cosmoO_newClosure(state, resFunc)));
|
|
||||||
|
|
||||||
// finally free out parser states
|
// finally free out parser states
|
||||||
endCompiler(&parser);
|
endCompiler(&parser);
|
||||||
freeParseState(&parser);
|
freeParseState(&parser);
|
||||||
|
|
||||||
|
// push the funciton onto the stack so if we cause an GC event, it won't be free'd
|
||||||
|
cosmoV_pushValue(state, cosmoV_newObj(resFunc));
|
||||||
cosmoM_unfreezeGC(state);
|
cosmoM_unfreezeGC(state);
|
||||||
|
cosmoV_pop(state);
|
||||||
return resFunc;
|
return resFunc;
|
||||||
}
|
}
|
||||||
|
12
src/cstate.c
12
src/cstate.c
@ -34,13 +34,17 @@ CState *cosmoV_newState() {
|
|||||||
|
|
||||||
state->error = NULL;
|
state->error = NULL;
|
||||||
|
|
||||||
cosmoT_initTable(state, &state->strings, 8); // init string table
|
// set default proto objects
|
||||||
cosmoT_initTable(state, &state->globals, 8); // init global table
|
for (int i = 0; i < COBJ_MAX; i++)
|
||||||
|
state->protoObjects[i] = NULL;
|
||||||
|
|
||||||
// first, set all strings to NULL so our GC doesn't read garbage data
|
// first, set all strings to NULL so our GC doesn't read garbage data
|
||||||
for (int i = 0; i < ISTRING_MAX; i++)
|
for (int i = 0; i < ISTRING_MAX; i++)
|
||||||
state->iStrings[i] = NULL;
|
state->iStrings[i] = NULL;
|
||||||
|
|
||||||
|
cosmoT_initTable(state, &state->strings, 8); // init string table
|
||||||
|
cosmoT_initTable(state, &state->globals, 8); // init global table
|
||||||
|
|
||||||
// setup all strings used by the VM
|
// setup all strings used by the VM
|
||||||
state->iStrings[ISTRING_INIT] = cosmoO_copyString(state, "__init", 6);
|
state->iStrings[ISTRING_INIT] = cosmoO_copyString(state, "__init", 6);
|
||||||
state->iStrings[ISTRING_TOSTRING] = cosmoO_copyString(state, "__tostring", 10);
|
state->iStrings[ISTRING_TOSTRING] = cosmoO_copyString(state, "__tostring", 10);
|
||||||
@ -62,10 +66,6 @@ CState *cosmoV_newState() {
|
|||||||
for (int i = 0; i < ISTRING_MAX; i++)
|
for (int i = 0; i < ISTRING_MAX; i++)
|
||||||
state->iStrings[i]->isIString = true;
|
state->iStrings[i]->isIString = true;
|
||||||
|
|
||||||
// set default proto objects
|
|
||||||
for (int i = 0; i < COBJ_MAX; i++)
|
|
||||||
state->protoObjects[i] = NULL;
|
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
44
src/ctable.c
44
src/ctable.c
@ -24,21 +24,24 @@ unsigned int nextPow2(unsigned int x) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cosmoT_initTable(CState *state, CTable *tbl, int startCap) {
|
void cosmoT_initTable(CState *state, CTable *tbl, int startCap) {
|
||||||
tbl->capacity = startCap != 0 ? startCap : ARRAY_START; // sanity check :P
|
startCap = startCap != 0 ? startCap : ARRAY_START; // sanity check :P
|
||||||
|
|
||||||
|
tbl->capacityMask = startCap - 1;
|
||||||
tbl->count = 0;
|
tbl->count = 0;
|
||||||
tbl->tombstones = 0;
|
tbl->tombstones = 0;
|
||||||
tbl->table = NULL; // to let out GC know we're initalizing
|
tbl->table = NULL; // to let out GC know we're initalizing
|
||||||
tbl->table = cosmoM_xmalloc(state, sizeof(CTableEntry) * tbl->capacity);
|
tbl->table = cosmoM_xmalloc(state, sizeof(CTableEntry) * startCap);
|
||||||
|
|
||||||
// init everything to NIL
|
// init everything to NIL
|
||||||
for (int i = 0; i < tbl->capacity; i++) {
|
for (int i = 0; i < startCap; i++) {
|
||||||
tbl->table[i].key = cosmoV_newNil();
|
tbl->table[i].key = cosmoV_newNil();
|
||||||
tbl->table[i].val = cosmoV_newNil();
|
tbl->table[i].val = cosmoV_newNil();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoT_addTable(CState *state, CTable *from, CTable *to) {
|
void cosmoT_addTable(CState *state, CTable *from, CTable *to) {
|
||||||
for (int i = 0; i < from->capacity; i++) {
|
int cap = from->capacityMask + 1;
|
||||||
|
for (int i = 0; i < cap; i++) {
|
||||||
CTableEntry *entry = &from->table[i];
|
CTableEntry *entry = &from->table[i];
|
||||||
|
|
||||||
if (!(IS_NIL(entry->key))) {
|
if (!(IS_NIL(entry->key))) {
|
||||||
@ -49,7 +52,7 @@ void cosmoT_addTable(CState *state, CTable *from, CTable *to) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cosmoT_clearTable(CState *state, CTable *tbl) {
|
void cosmoT_clearTable(CState *state, CTable *tbl) {
|
||||||
cosmoM_freearray(state, CTableEntry, tbl->table, tbl->capacity);
|
cosmoM_freearray(state, CTableEntry, tbl->table, (tbl->capacityMask + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getObjectHash(CObj *obj) {
|
uint32_t getObjectHash(CObj *obj) {
|
||||||
@ -57,7 +60,7 @@ uint32_t getObjectHash(CObj *obj) {
|
|||||||
case COBJ_STRING:
|
case COBJ_STRING:
|
||||||
return ((CObjString*)obj)->hash;
|
return ((CObjString*)obj)->hash;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return (uint32_t)obj; // just "hash" the pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,13 +118,16 @@ static void resizeTbl(CState *state, CTable *tbl, int newCapacity, bool canShrin
|
|||||||
|
|
||||||
size_t size = sizeof(CTableEntry) * newCapacity;
|
size_t size = sizeof(CTableEntry) * newCapacity;
|
||||||
int cachedCount = tbl->count;
|
int cachedCount = tbl->count;
|
||||||
|
int newCount, oldCap;
|
||||||
|
|
||||||
cosmoM_checkGarbage(state, size); // if this allocation would cause a GC, run the GC
|
cosmoM_checkGarbage(state, size); // if this allocation would cause a GC, run the GC
|
||||||
|
|
||||||
if (tbl->count < cachedCount) // the GC removed some objects from this table and resized it, ignore our resize event!
|
if (tbl->count < cachedCount) // the GC removed some objects from this table and resized it, ignore our resize event!
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CTableEntry *entries = cosmoM_xmalloc(state, size);
|
CTableEntry *entries = cosmoM_xmalloc(state, size);
|
||||||
int newCount = 0;
|
oldCap = tbl->capacityMask + 1;
|
||||||
|
newCount = 0;
|
||||||
|
|
||||||
// set all nodes as NIL : NIL
|
// set all nodes as NIL : NIL
|
||||||
for (int i = 0; i < newCapacity; i++) {
|
for (int i = 0; i < newCapacity; i++) {
|
||||||
@ -130,7 +136,7 @@ static void resizeTbl(CState *state, CTable *tbl, int newCapacity, bool canShrin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// move over old values to the new buffer
|
// move over old values to the new buffer
|
||||||
for (int i = 0; i < tbl->capacity; i++) {
|
for (int i = 0; i < oldCap; i++) {
|
||||||
CTableEntry *oldEntry = &tbl->table[i];
|
CTableEntry *oldEntry = &tbl->table[i];
|
||||||
if (IS_NIL(oldEntry->key))
|
if (IS_NIL(oldEntry->key))
|
||||||
continue; // skip empty keys
|
continue; // skip empty keys
|
||||||
@ -143,10 +149,10 @@ static void resizeTbl(CState *state, CTable *tbl, int newCapacity, bool canShrin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// free the old table
|
// free the old table
|
||||||
cosmoM_freearray(state, CTableEntry, tbl->table, tbl->capacity);
|
cosmoM_freearray(state, CTableEntry, tbl->table, oldCap);
|
||||||
|
|
||||||
tbl->table = entries;
|
tbl->table = entries;
|
||||||
tbl->capacity = newCapacity;
|
tbl->capacityMask = newCapacity - 1;
|
||||||
tbl->count = newCount;
|
tbl->count = newCount;
|
||||||
tbl->tombstones = 0;
|
tbl->tombstones = 0;
|
||||||
}
|
}
|
||||||
@ -164,14 +170,15 @@ bool cosmoT_checkShrink(CState *state, CTable *tbl) {
|
|||||||
// returns a pointer to the allocated value
|
// returns a pointer to the allocated value
|
||||||
COSMO_API CValue* cosmoT_insert(CState *state, CTable *tbl, CValue key) {
|
COSMO_API CValue* cosmoT_insert(CState *state, CTable *tbl, CValue key) {
|
||||||
// make sure we have enough space allocated
|
// make sure we have enough space allocated
|
||||||
if (tbl->count + 1 > (int)(tbl->capacity * MAX_TABLE_FILL)) {
|
int cap = tbl->capacityMask + 1;
|
||||||
|
if (tbl->count + 1 > (int)(cap * MAX_TABLE_FILL)) {
|
||||||
// grow table
|
// grow table
|
||||||
int newCap = tbl->capacity * GROW_FACTOR;
|
int newCap = cap * GROW_FACTOR;
|
||||||
resizeTbl(state, tbl, newCap, true);
|
resizeTbl(state, tbl, newCap, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert into the table
|
// insert into the table
|
||||||
CTableEntry *entry = findEntry(tbl->table, tbl->capacity - 1, key); // -1 for our capacity mask
|
CTableEntry *entry = findEntry(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,7 +198,7 @@ bool cosmoT_get(CTable *tbl, CValue key, CValue *val) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CTableEntry *entry = findEntry(tbl->table, tbl->capacity - 1, key);
|
CTableEntry *entry = findEntry(tbl->table, tbl->capacityMask, key);
|
||||||
*val = entry->val;
|
*val = entry->val;
|
||||||
|
|
||||||
// return if get was successful
|
// return if get was successful
|
||||||
@ -201,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->capacity - 1, key);
|
CTableEntry *entry = findEntry(tbl->table, tbl->capacityMask, key);
|
||||||
if (IS_NIL(entry->key)) // sanity check
|
if (IS_NIL(entry->key)) // sanity check
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -220,7 +227,7 @@ COSMO_API int cosmoT_count(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) {
|
||||||
if (tbl->count == 0) return 0; // sanity check
|
if (tbl->count == 0) return 0; // sanity check
|
||||||
uint32_t indx = hash & (tbl->capacity - 1); // 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 & tbl->capacityMask; // since we know the capacity will *always* be a power of 2, we can use bitwise & to perform a MUCH faster mod operation
|
||||||
|
|
||||||
// keep looking for an open slot in the entries array
|
// keep looking for an open slot in the entries array
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -234,14 +241,15 @@ CObjString *cosmoT_lookupString(CTable *tbl, const char *str, int length, uint32
|
|||||||
return (CObjString*)cosmoV_readObj(entry->key);
|
return (CObjString*)cosmoV_readObj(entry->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
indx = (indx + 1) & (tbl->capacity - 1); // fast mod here too
|
indx = (indx + 1) & tbl->capacityMask; // fast mod here too
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for debugging purposes
|
// for debugging purposes
|
||||||
void cosmoT_printTable(CTable *tbl, const char *name) {
|
void cosmoT_printTable(CTable *tbl, const char *name) {
|
||||||
printf("==== [[%s]] ====\n", name);
|
printf("==== [[%s]] ====\n", name);
|
||||||
for (int i = 0; i < tbl->capacity; i++) {
|
int cap = tbl->capacityMask + 1;
|
||||||
|
for (int i = 0; i < cap; i++) {
|
||||||
CTableEntry *entry = &tbl->table[i];
|
CTableEntry *entry = &tbl->table[i];
|
||||||
if (!(IS_NIL(entry->key))) {
|
if (!(IS_NIL(entry->key))) {
|
||||||
printValue(entry->key);
|
printValue(entry->key);
|
||||||
|
@ -13,20 +13,19 @@ typedef struct CTableEntry {
|
|||||||
|
|
||||||
typedef struct CTable {
|
typedef struct CTable {
|
||||||
int count;
|
int count;
|
||||||
int capacity;
|
int capacityMask; // +1 to get the capacity
|
||||||
int tombstones;
|
int tombstones;
|
||||||
CTableEntry *table;
|
CTableEntry *table;
|
||||||
} CTable;
|
} CTable;
|
||||||
|
|
||||||
COSMO_API void cosmoT_initTable(CState *state, CTable *tbl, int startCap);
|
COSMO_API void cosmoT_initTable(CState *state, CTable *tbl, int startCap);
|
||||||
COSMO_API void cosmoT_clearTable(CState *state, CTable *tbl);
|
COSMO_API void cosmoT_clearTable(CState *state, CTable *tbl);
|
||||||
COSMO_API void cosmoT_addTable(CState *state, CTable *from, CTable *to);
|
|
||||||
COSMO_API int cosmoT_count(CTable *tbl);
|
COSMO_API int cosmoT_count(CTable *tbl);
|
||||||
|
|
||||||
bool cosmoT_checkShrink(CState *state, CTable *tbl);
|
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);
|
||||||
COSMO_API 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(CTable *tbl, CValue key, CValue *val);
|
||||||
bool cosmoT_remove(CState *state, CTable *tbl, CValue key);
|
bool cosmoT_remove(CState *state, CTable *tbl, CValue key);
|
||||||
|
|
||||||
|
25
src/cvm.c
25
src/cvm.c
@ -2,6 +2,7 @@
|
|||||||
#include "cstate.h"
|
#include "cstate.h"
|
||||||
#include "cdebug.h"
|
#include "cdebug.h"
|
||||||
#include "cmem.h"
|
#include "cmem.h"
|
||||||
|
#include "cparse.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -27,7 +28,26 @@ COSMO_API void cosmo_insert(CState *state, int indx, CValue val) {
|
|||||||
state->top++;
|
state->top++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cosmoV_printError(CState *state, CObjError *err) {
|
COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *name) {
|
||||||
|
CObjFunction *func;
|
||||||
|
|
||||||
|
if ((func = cosmoP_compileString(state, src, name)) != NULL) {
|
||||||
|
// success
|
||||||
|
disasmChunk(&func->chunk, func->module->str, 0);
|
||||||
|
|
||||||
|
// push function onto the stack so it doesn't it cleaned up by the GC, at the same stack location put our closure
|
||||||
|
cosmoV_pushValue(state, cosmoV_newObj(func));
|
||||||
|
*(cosmoV_getTop(state, 0)) = cosmoV_newObj(cosmoO_newClosure(state, func));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail
|
||||||
|
state->panic = false;
|
||||||
|
cosmoV_pushValue(state, cosmoV_newObj(state->error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
COSMO_API void cosmoV_printError(CState *state, CObjError *err) {
|
||||||
// print stack trace
|
// print stack trace
|
||||||
for (int i = 0; i < err->frameCount; i++) {
|
for (int i = 0; i < err->frameCount; i++) {
|
||||||
CCallFrame *frame = &err->frames[i];
|
CCallFrame *frame = &err->frames[i];
|
||||||
@ -473,10 +493,11 @@ int _tbl__next(CState *state, int nargs, CValue *args) {
|
|||||||
CObjTable *table = (CObjTable*)cosmoV_readObj(val);
|
CObjTable *table = (CObjTable*)cosmoV_readObj(val);
|
||||||
|
|
||||||
// while the entry is invalid, go to the next entry
|
// while the entry is invalid, go to the next entry
|
||||||
|
int cap = table->tbl.capacityMask + 1;
|
||||||
CTableEntry *entry;
|
CTableEntry *entry;
|
||||||
do {
|
do {
|
||||||
entry = &table->tbl.table[index++];
|
entry = &table->tbl.table[index++];
|
||||||
} while (IS_NIL(entry->key) && index < table->tbl.capacity);
|
} while (IS_NIL(entry->key) && index < cap);
|
||||||
cosmoO_setUserI(state, obj, index); // update the userdata
|
cosmoO_setUserI(state, obj, index); // update the userdata
|
||||||
|
|
||||||
if (!IS_NIL(entry->key)) { // if the entry is valid, return it's key and value pair
|
if (!IS_NIL(entry->key)) { // if the entry is valid, return it's key and value pair
|
||||||
|
@ -24,6 +24,15 @@ COSMO_API CObjError* cosmoV_throw(CState *state);
|
|||||||
COSMO_API void cosmoV_error(CState *state, const char *format, ...);
|
COSMO_API void cosmoV_error(CState *state, const char *format, ...);
|
||||||
COSMO_API void cosmo_insert(CState *state, int indx, CValue val);
|
COSMO_API void cosmo_insert(CState *state, int indx, CValue val);
|
||||||
|
|
||||||
|
/*
|
||||||
|
compiles string into a <closure>, if successful, <closure> will be pushed onto the stack otherwise the <error> will be pushed.
|
||||||
|
|
||||||
|
returns:
|
||||||
|
false : <error> is at the top of the stack
|
||||||
|
true : <closure> is at the top of the stack
|
||||||
|
*/
|
||||||
|
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_get(CState *state, CObj *obj, CValue key, CValue *val);
|
||||||
COSMO_API bool cosmoV_set(CState *state, CObj *obj, CValue key, CValue val);
|
COSMO_API bool cosmoV_set(CState *state, CObj *obj, CValue key, CValue val);
|
||||||
|
|
||||||
|
@ -32,16 +32,14 @@ int cosmoB_input(CState *state, int nargs, CValue *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void interpret(CState *state, const char *script, const char *mod) {
|
static void interpret(CState *state, const char *script, const char *mod) {
|
||||||
// cosmoP_compileString pushes the result onto the stack (NIL or COBJ_CLOSURE)
|
// cosmoV_compileString pushes the result onto the stack (COBJ_ERROR or COBJ_CLOSURE)
|
||||||
CObjFunction* func = cosmoP_compileString(state, script, mod);
|
if (cosmoV_compileString(state, script, mod)) {
|
||||||
if (func != NULL) {
|
|
||||||
disasmChunk(&func->chunk, func->name != NULL ? func->name->str : "_main", 0);
|
|
||||||
|
|
||||||
COSMOVMRESULT res = cosmoV_call(state, 0, 0); // 0 args being passed, 0 results expected
|
COSMOVMRESULT res = cosmoV_call(state, 0, 0); // 0 args being passed, 0 results expected
|
||||||
|
|
||||||
if (res == COSMOVM_RUNTIME_ERR)
|
if (res == COSMOVM_RUNTIME_ERR)
|
||||||
cosmoV_printError(state, state->error);
|
cosmoV_printError(state, state->error);
|
||||||
} else {
|
} else {
|
||||||
|
cosmoV_pop(state); // pop the error off the stack
|
||||||
cosmoV_printError(state, state->error);
|
cosmoV_printError(state, state->error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user