Dictionaries -> Tables

Tables are going to become a more generic form of data storage. While objects will be "stateful", tables will remain static.

'{}' now refers to an object declaration, '[]' will be reserved for tables.
This commit is contained in:
CPunch 2021-01-08 14:37:36 -06:00
parent e57c194837
commit 824c0e89b9
9 changed files with 123 additions and 92 deletions

View File

@ -126,7 +126,7 @@ void cosmoB_loadLibrary(CState *state) {
cosmoV_pushString(state, "sub");
cosmoV_pushCFunction(state, cosmoB_sSub);
cosmoV_makeDictionary(state, 1);
cosmoV_makeTable(state, 1);
// string.
// register these all to the global table
@ -177,7 +177,7 @@ void cosmoB_loadDebug(CState *state) {
cosmoV_pushString(state, "__proto"); // key
cosmoV_pushCFunction(state, cosmoB_dgetProto); // value
cosmoV_makeDictionary(state, 1);
cosmoV_makeTable(state, 1);
// make __setter object
cosmoV_pushString(state, "__setter");
@ -185,7 +185,7 @@ void cosmoB_loadDebug(CState *state) {
cosmoV_pushString(state, "__proto");
cosmoV_pushCFunction(state, cosmoB_dsetProto);
cosmoV_makeDictionary(state, 1);
cosmoV_makeTable(state, 1);
// we call makeObject leting it know there are 2 sets of key & value pairs on the stack
cosmoV_makeObject(state, 2);

View File

@ -123,8 +123,8 @@ int disasmInstr(CChunk *chunk, int offset, int indent) {
}
case OP_CLOSE:
return simpleInstruction("OP_CLOSE", offset);
case OP_NEWDICT:
return u16OperandInstruction("OP_NEWDICT", chunk, offset);
case OP_NEWTABLE:
return u16OperandInstruction("OP_NEWTABLE", chunk, offset);
case OP_INDEX:
return simpleInstruction("OP_INDEX", offset);
case OP_NEWINDEX:

View File

@ -97,9 +97,9 @@ void blackenObject(CState *state, CObj *obj) {
markTable(state, &cobj->tbl);
break;
}
case COBJ_DICT: { // dictionaries are just wrappers for CTable
CObjDict *dict = (CObjDict*)obj;
markTable(state, &dict->tbl);
case COBJ_TABLE: { // tables are just wrappers for CTable
CObjTable *tbl = (CObjTable*)obj;
markTable(state, &tbl->tbl);
break;
}
case COBJ_UPVALUE: {

View File

@ -53,10 +53,10 @@ void cosmoO_free(CState *state, CObj* obj) {
cosmoM_free(state, CObjObject, objTbl);
break;
}
case COBJ_DICT: {
CObjDict *dict = (CObjDict*)obj;
cosmoT_clearTable(state, &dict->tbl);
cosmoM_free(state, CObjDict, dict);
case COBJ_TABLE: {
CObjTable *tbl = (CObjTable*)obj;
cosmoT_clearTable(state, &tbl->tbl);
cosmoM_free(state, CObjTable, tbl);
break;
}
case COBJ_UPVALUE: {
@ -121,8 +121,8 @@ CObjObject *cosmoO_newObject(CState *state) {
return obj;
}
CObjDict *cosmoO_newDictionary(CState *state) {
CObjDict *obj = (CObjDict*)cosmoO_allocateBase(state, sizeof(CObjDict), COBJ_DICT);
CObjTable *cosmoO_newTable(CState *state) {
CObjTable *obj = (CObjTable*)cosmoO_allocateBase(state, sizeof(CObjTable), COBJ_TABLE);
// init the table (might cause a GC event)
cosmoV_pushValue(state, cosmoV_newObj(obj)); // so our GC can keep track of obj
@ -448,9 +448,9 @@ CObjString *cosmoO_toString(CState *state, CObj *obj) {
CObjError *err = (CObjError*)obj;
return cosmoV_toString(state, err->err);
}
case COBJ_DICT: {
case COBJ_TABLE: {
char buf[64];
int sz = sprintf(buf, "<dict> %p", (void*)obj) + 1; // +1 for the null character
int sz = sprintf(buf, "<tbl> %p", (void*)obj) + 1; // +1 for the null character
return cosmoO_copyString(state, buf, sz);
}
default:
@ -469,9 +469,9 @@ void printObject(CObj *o) {
printf("<obj> %p", (void*)o);
break;
}
case COBJ_DICT: {
CObjDict *dict = (CObjDict*)o;
printf("<dict> %p", (void*)dict);
case COBJ_TABLE: {
CObjTable *tbl = (CObjTable*)o;
printf("<tbl> %p", (void*)tbl);
break;
}
case COBJ_UPVALUE: {
@ -513,7 +513,7 @@ const char *cosmoO_typeStr(CObj* obj) {
switch (obj->type) {
case COBJ_STRING: return "<string>";
case COBJ_OBJECT: return "<object>";
case COBJ_DICT: return "<dictionary>";
case COBJ_TABLE: return "<table>";
case COBJ_FUNCTION: return "<function>";
case COBJ_CFUNCTION: return "<c function>";
case COBJ_METHOD: return "<method>";

View File

@ -6,7 +6,7 @@
typedef enum {
COBJ_STRING,
COBJ_OBJECT,
COBJ_DICT, // dictionary
COBJ_TABLE,
COBJ_FUNCTION,
COBJ_CFUNCTION,
COBJ_ERROR,
@ -67,10 +67,10 @@ typedef struct CObjObject {
};
} CObjObject;
typedef struct CObjDict { // dictionary, a wrapper for CTable
typedef struct CObjTable { // table, a wrapper for CTable
CommonHeader; // "is a" CObj
CTable tbl;
} CObjDict;
} CObjTable;
typedef struct CObjFunction {
CommonHeader; // "is a" CObj
@ -111,7 +111,7 @@ typedef struct CObjUpval {
#define IS_STRING(x) isObjType(x, COBJ_STRING)
#define IS_OBJECT(x) isObjType(x, COBJ_OBJECT)
#define IS_DICT(x) isObjType(x, COBJ_DICT)
#define IS_TABLE(x) isObjType(x, COBJ_TABLE)
#define IS_FUNCTION(x) isObjType(x, COBJ_FUNCTION)
#define IS_CFUNCTION(x) isObjType(x, COBJ_CFUNCTION)
#define IS_METHOD(x) isObjType(x, COBJ_METHOD)
@ -139,7 +139,7 @@ void cosmoO_free(CState *state, CObj* obj);
bool cosmoO_equal(CObj* obj1, CObj* obj2);
CObjObject *cosmoO_newObject(CState *state);
CObjDict *cosmoO_newDictionary(CState *state);
CObjTable *cosmoO_newTable(CState *state);
CObjFunction *cosmoO_newFunction(CState *state);
CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func);
CObjError *cosmoO_newError(CState *state, CValue err);

View File

@ -22,7 +22,7 @@ typedef enum {
OP_CALL, // calls top[-uint8_t] expecting uint8_t results
OP_CLOSURE,
OP_CLOSE,
OP_NEWDICT,
OP_NEWTABLE,
OP_INDEX,
OP_NEWINDEX,
OP_NEWOBJECT,
@ -45,7 +45,7 @@ typedef enum {
OP_INCLOCAL, // pushes old value to stack, adds (uint8_t-128) to local[uint8_t]
OP_INCGLOBAL, // pushes old value to stack, adds (uint8_t-128) to globals[const[uint16_t]]
OP_INCUPVAL, // pushes old value to stack, adds (uint8_t-128) to closure->upval[uint8_t]
OP_INCINDEX, // pushes old value to stack, adds (uint8_t-128) to dict[pop()]
OP_INCINDEX,
OP_INCOBJECT, // pushes old value to stack, adds (uint8_t-128) to obj[const[uint16_t]]
// EQUALITY

View File

@ -621,6 +621,34 @@ static void call_(CParseState *pstate, bool canAssign, Precedence prec) {
valuePushed(pstate, returnNum);
}
static void table(CParseState *pstate, bool canAssign, Precedence prec) {
// enter having already consumed '['
int entries = 0;
int tblType = 0; // 0 = we don't know yet / 1 = array-like table / 2 = dictionary-like table
if (!match(pstate, TOKEN_RIGHT_BRACKET)) {
do {
// grab value/key
expression(pstate, 1, true);
// they want to make a table with key:value
if (match(pstate, TOKEN_COLON) && tblType != 1) {
tblType = 2; // dictionary-like
// grab value
expression(pstate, 1, true);
} else if ((check(pstate, TOKEN_COMMA) || check(pstate, TOKEN_RIGHT_BRACKET)) && tblType != 2) {
tblType = 1; // array-like
} else {
error(pstate, "Can't change table description type mid-definition!");
return;
}
entries++;
} while (match(pstate, TOKEN_COMMA));
}
}
static void object(CParseState *pstate, bool canAssign, Precedence prec) {
// already consumed the beginning '{'
int entries = 0;
@ -628,22 +656,25 @@ static void object(CParseState *pstate, bool canAssign, Precedence prec) {
if (!match(pstate, TOKEN_RIGHT_BRACE)) {
do {
// parse the key first
expression(pstate, 1, true); // should parse until ':'
consume(pstate, TOKEN_IDENTIFIER, "Expected property identifier before '='!");
uint16_t ident = identifierConstant(pstate, &pstate->previous);
writeu8(pstate, OP_LOADCONST);
writeu16(pstate, ident);
consume(pstate, TOKEN_COLON, "Expected ':' to mark end of key and start of value!");
consume(pstate, TOKEN_EQUAL, "Expected '=' to mark the start of value!");
// now, parse the value (until comma)
expression(pstate, 1, true);
// "pop" the 2 values
valuePopped(pstate, 2);
// "pop" the 1 value
valuePopped(pstate, 1);
entries++;
} while (match(pstate, TOKEN_COMMA) && !pstate->hadError);
consume(pstate, TOKEN_RIGHT_BRACE, "Expected '}' to end object definition.");
}
writeu8(pstate, OP_NEWDICT); // creates a dictionary with u16 entries
writeu8(pstate, OP_NEWOBJECT); // creates a object with u16 entries
writeu16(pstate, entries);
valuePushed(pstate, 1);
}
@ -725,7 +756,7 @@ static void walkIndexes(CParseState *pstate, int lastIndexType, uint16_t lastIde
break;
case 1: // []
writeu8(pstate, OP_INDEX); // so, that was a normal index, perform that
valuePopped(pstate, 1); // pops the key & dict off the stack, but pushes the value
valuePopped(pstate, 1); // pops the key & table off the stack, but pushes the value
break;
default: // no previous index
break;
@ -750,7 +781,7 @@ static void walkIndexes(CParseState *pstate, int lastIndexType, uint16_t lastIde
case 1: // []
writeu8(pstate, OP_INCINDEX);
writeu8(pstate, 128 + val);
valuePopped(pstate, 2); // popped the dictionary & the key off the stack, but pushes the previous value
valuePopped(pstate, 2); // popped the table & the key off the stack, but pushes the previous value
break;
default: // no previous index
break;
@ -766,8 +797,8 @@ static void increment(CParseState *pstate, int val) {
// walk the indexes
walkIndexes(pstate, 0, ident, val);
} else if (match(pstate, TOKEN_LEFT_BRACKET)) { // dictionary?
namedVariable(pstate, name, false, false, 0); // just get the dictionary
} else if (match(pstate, TOKEN_LEFT_BRACKET)) { // table?
namedVariable(pstate, name, false, false, 0); // just get the table
// grab key
expression(pstate, 1, true);
@ -1174,8 +1205,8 @@ static void function(CParseState *pstate, FunctionType type) {
} while (match(pstate, TOKEN_COMMA));
}
if (match(pstate, TOKEN_DOT_DOT_DOT)) { // marks a function as variadic, now we expect an identifer for the populated variadic dictionary
uint16_t vari = parseVariable(pstate, "Expected identifier for variadic dictionary!", true);
if (match(pstate, TOKEN_DOT_DOT_DOT)) { // marks a function as variadic, now we expect an identifer for the populated variadic table
uint16_t vari = parseVariable(pstate, "Expected identifier for variadic table!", true);
defineVariable(pstate, vari, true);
valuePushed(pstate, 1);
compiler.function->variadic = true;
@ -1271,7 +1302,7 @@ static void forEachLoop(CParseState *pstate) {
return;
}
// after we consume the values, get the dictionary/object/whatever on the stack
// after we consume the values, get the table/object/whatever on the stack
consume(pstate, TOKEN_IN, "Expected 'in' before iterator!");
expression(pstate, 1, true);

104
src/cvm.c
View File

@ -225,7 +225,7 @@ static bool callCFunction(CState *state, CosmoCFunction cfunc, int args, int nre
static bool rawCall(CState *state, CObjClosure *closure, int args, int nresults, int offset) {
CObjFunction *func = closure->function;
// if the function is variadic and theres more args than parameters, push the args into a dictionary
// if the function is variadic and theres more args than parameters, push the args into a table
if (func->variadic && args >= func->args) {
int extraArgs = args - func->args;
StkPtr variStart = cosmoV_getTop(state, extraArgs-1);
@ -236,8 +236,8 @@ static bool rawCall(CState *state, CObjClosure *closure, int args, int nresults,
cosmoV_pushValue(state, *(variStart + i));
}
cosmoV_makeDictionary(state, extraArgs);
*variStart = *cosmoV_getTop(state, 0); // move dict on the stack to the vari local
cosmoV_makeTable(state, extraArgs);
*variStart = *cosmoV_getTop(state, 0); // move table on the stack to the vari local
state->top -= extraArgs;
pushCallFrame(state, closure, func->args + 1);
@ -390,10 +390,10 @@ COSMO_API void cosmoV_makeObject(CState *state, int pairs) {
cosmoV_pushValue(state, cosmoV_newObj(newObj));
}
COSMO_API void cosmoV_makeDictionary(CState *state, int pairs) {
COSMO_API void cosmoV_makeTable(CState *state, int pairs) {
StkPtr key, val;
CObjDict *newObj = cosmoO_newDictionary(state);
cosmoV_pushValue(state, cosmoV_newObj(newObj)); // so our GC doesn't free our new dictionary
CObjTable *newObj = cosmoO_newTable(state);
cosmoV_pushValue(state, cosmoV_newObj(newObj)); // so our GC doesn't free our new table
for (int i = 0; i < pairs; i++) {
val = cosmoV_getTop(state, (i*2) + 1);
@ -404,8 +404,8 @@ COSMO_API void cosmoV_makeDictionary(CState *state, int pairs) {
*newVal = *val;
}
// once done, pop everything off the stack + push new dictionary
cosmoV_setTop(state, (pairs * 2) + 1); // + 1 for our dictionary
// once done, pop everything off the stack + push new table
cosmoV_setTop(state, (pairs * 2) + 1); // + 1 for our table
cosmoV_pushValue(state, cosmoV_newObj(newObj));
}
@ -449,7 +449,7 @@ COSMO_API bool cosmoV_set(CState *state, CObj *_obj, CValue key, CValue val) {
return true;
}
int _dict__next(CState *state, int nargs, CValue *args) {
int _tbl__next(CState *state, int nargs, CValue *args) {
if (nargs != 1) {
cosmoV_error(state, "Expected 1 parameter, %d received!", nargs);
return 0;
@ -466,17 +466,17 @@ int _dict__next(CState *state, int nargs, CValue *args) {
cosmoO_getIString(state, obj, ISTRING_RESERVED, &val);
if (!IS_DICT(val)) {
if (!IS_TABLE(val)) {
return 0; // someone set the __reserved member to something else. this will exit the iterator loop
}
CObjDict *dict = (CObjDict*)cosmoV_readObj(val);
CObjTable *table = (CObjTable*)cosmoV_readObj(val);
// while the entry is invalid, go to the next entry
CTableEntry *entry;
do {
entry = &dict->tbl.table[index++];
} while (IS_NIL(entry->key) && index < dict->tbl.capacity);
entry = &table->tbl.table[index++];
} while (IS_NIL(entry->key) && index < table->tbl.capacity);
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
@ -614,24 +614,24 @@ int cosmoV_execute(CState *state) {
cosmoV_pop(state);
break;
}
case OP_NEWDICT: {
case OP_NEWTABLE: {
uint16_t pairs = READUINT();
cosmoV_makeDictionary(state, pairs);
cosmoV_makeTable(state, pairs);
break;
}
case OP_INDEX: {
StkPtr key = cosmoV_getTop(state, 0); // key should be the top of the stack
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the dictionary
StkPtr temp = cosmoV_getTop(state, 1); // after that should be the table
// sanity check
if (IS_OBJ(*temp)) {
CValue val; // to hold our value
switch (cosmoV_readObj(*temp)->type) {
case COBJ_DICT: {
CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp);
case COBJ_TABLE: {
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
cosmoT_get(&dict->tbl, *key, &val);
cosmoT_get(&tbl->tbl, *key, &val);
break;
}
default: { // check for __index metamethod
@ -665,9 +665,9 @@ int cosmoV_execute(CState *state) {
// sanity check
if (IS_OBJ(*temp)) {
switch (cosmoV_readObj(*temp)->type) {
case COBJ_DICT: { // index and set table
CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp);
CValue *newVal = cosmoT_insert(state, &dict->tbl, *key);
case COBJ_TABLE: { // index and set table
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
CValue *newVal = cosmoT_insert(state, &tbl->tbl, *key);
*newVal = *value; // set the index
break;
@ -709,10 +709,10 @@ int cosmoV_execute(CState *state) {
// sanity check
if (IS_OBJ(*temp)) {
switch (cosmoV_readObj(*temp)->type) {
case COBJ_DICT: { // syntax sugar, makes "namespaces" possible
CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp);
case COBJ_TABLE: { // syntax sugar, makes "namespaces" possible
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
cosmoT_get(&dict->tbl, constants[ident], &val);
cosmoT_get(&tbl->tbl, constants[ident], &val);
break;
}
default:
@ -736,9 +736,9 @@ int cosmoV_execute(CState *state) {
// sanity check
if (IS_OBJ(*temp)) {
switch (cosmoV_readObj(*temp)->type) {
case COBJ_DICT: { // index and set the table
CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp);
CValue *newVal = cosmoT_insert(state, &dict->tbl, constants[ident]);
case COBJ_TABLE: { // index and set the table
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
CValue *newVal = cosmoT_insert(state, &tbl->tbl, constants[ident]);
*newVal = *value; // set the index
break;
@ -757,19 +757,19 @@ int cosmoV_execute(CState *state) {
break;
}
case OP_INVOKE: { // this is an optimization made by the parser, instead of allocating a CObjMethod every time we want to invoke a method, we shrink it down into one minimal instruction!
CValue val; // to hold our value
uint8_t args = READBYTE();
uint8_t nres = READBYTE();
uint16_t ident = READUINT();
StkPtr temp = cosmoV_getTop(state, args); // grabs object from stack
CValue val; // to hold our value
// sanity check
if (IS_OBJ(*temp)) {
switch (cosmoV_readObj(*temp)->type) {
case COBJ_DICT: { // again, syntax sugar ("""""namespaces""""")
CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp);
case COBJ_TABLE: { // again, syntax sugar ("""""namespaces""""")
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
cosmoT_get(&dict->tbl, constants[ident], &val);
cosmoT_get(&tbl->tbl, constants[ident], &val);
// call closure/cfunction
if (!callCValue(state, val, args, nres, 0))
@ -799,7 +799,7 @@ int cosmoV_execute(CState *state) {
break;
}
case OP_ITER: {
StkPtr temp = cosmoV_getTop(state, 0); // should be the object/dictionary
StkPtr temp = cosmoV_getTop(state, 0); // should be the object/table
if (!IS_OBJ(*temp)) {
cosmoV_error(state, "Couldn't iterate over non-iterator type %s!", cosmoV_typeStr(*temp));
@ -808,15 +808,15 @@ int cosmoV_execute(CState *state) {
CObj *obj = cosmoV_readObj(*temp);
switch (obj->type) {
case COBJ_DICT: {
CObjDict *dict = (CObjDict*)obj;
case COBJ_TABLE: {
CObjTable *tbl = (CObjTable*)obj;
cosmoV_pushValue(state, cosmoV_newObj(state->iStrings[ISTRING_RESERVED])); // key
cosmoV_pushValue(state, cosmoV_newObj(dict)); // value
cosmoV_pushValue(state, cosmoV_newObj(tbl)); // value
cosmoV_pushString(state, "__next"); // key
CObjCFunction *dict_next = cosmoO_newCFunction(state, _dict__next);
cosmoV_pushValue(state, cosmoV_newObj(dict_next)); // value
CObjCFunction *tbl_next = cosmoO_newCFunction(state, _tbl__next);
cosmoV_pushValue(state, cosmoV_newObj(tbl_next)); // value
cosmoV_makeObject(state, 2); // pushes the new object to the stack
@ -824,9 +824,9 @@ int cosmoV_execute(CState *state) {
cosmoO_setUserI(state, obj, 0); // increment for iterator
// make our CObjMethod for OP_NEXT to call
CObjMethod *method = cosmoO_newMethod(state, cosmoV_newObj(dict_next), (CObj*)obj);
CObjMethod *method = cosmoO_newMethod(state, cosmoV_newObj(tbl_next), (CObj*)obj);
cosmoV_setTop(state, 2); // pops the object & the dict
cosmoV_setTop(state, 2); // pops the object & the tbl
cosmoV_pushValue(state, cosmoV_newObj(method)); // pushes the method for OP_NEXT
break;
}
@ -930,17 +930,17 @@ int cosmoV_execute(CState *state) {
}
break;
}
case OP_COUNT: { // pop 1 value off the stack & if it's a dictionary return the amount of active entries it has
case OP_COUNT: { // pop 1 value off the stack & if it's a table return the amount of active entries it has
StkPtr temp = cosmoV_getTop(state, 0);
if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_DICT) {
if (!IS_OBJ(*temp) || cosmoV_readObj(*temp)->type != COBJ_TABLE) {
cosmoV_error(state, "Expected object, got %s!", cosmoV_typeStr(*temp));
return -1;
}
CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp);
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
cosmoV_pop(state);
cosmoV_pushNumber(state, cosmoT_count(&dict->tbl)); // pushes the count onto the stack
cosmoV_pushNumber(state, cosmoT_count(&tbl->tbl)); // pushes the count onto the stack
break;
}
case OP_CONCAT: {
@ -1004,11 +1004,11 @@ int cosmoV_execute(CState *state) {
if (IS_OBJ(*temp)) {
switch (cosmoV_readObj(*temp)->type) {
case COBJ_DICT: {
CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp);
CValue *val = cosmoT_insert(state, &dict->tbl, *key);
case COBJ_TABLE: {
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
CValue *val = cosmoT_insert(state, &tbl->tbl, *key);
// pops dict & key from stack
// pops tbl & key from stack
cosmoV_setTop(state, 2);
if (IS_NUMBER(*val)) {
@ -1063,11 +1063,11 @@ int cosmoV_execute(CState *state) {
// sanity check
if (IS_OBJ(*temp)) {
switch (cosmoV_readObj(*temp)->type) {
case COBJ_DICT: {
CObjDict *dict = (CObjDict*)cosmoV_readObj(*temp);
CValue *val = cosmoT_insert(state, &dict->tbl, ident);
case COBJ_TABLE: {
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp);
CValue *val = cosmoT_insert(state, &tbl->tbl, ident);
// pops dict from stack
// pops tbl from stack
cosmoV_pop(state);
if (IS_NUMBER(*val)) {

View File

@ -16,7 +16,7 @@ typedef enum {
COSMO_API COSMOVMRESULT cosmoV_call(CState *state, int args, int nresults);
COSMO_API COSMOVMRESULT cosmoV_pcall(CState *state, int args, int nresults);
COSMO_API void cosmoV_makeObject(CState *state, int pairs);
COSMO_API void cosmoV_makeDictionary(CState *state, int pairs);
COSMO_API void cosmoV_makeTable(CState *state, int pairs);
COSMO_API void cosmoV_concat(CState *state, int vals);
COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...);
COSMO_API void cosmoV_printError(CState *state, CObjError *err);