diff --git a/src/cbaselib.c b/src/cbaselib.c index 1f38d09..b5f41c1 100644 --- a/src/cbaselib.c +++ b/src/cbaselib.c @@ -7,6 +7,7 @@ void cosmoB_loadLibrary(CState *state) { cosmoM_freezeGC(state); cosmoV_register(state, "print", cosmoV_newObj(cosmoO_newCFunction(state, cosmoB_print))); + cosmoV_register(state, "foreach", cosmoV_newObj(cosmoO_newCFunction(state, cosmoB_foreach))); cosmoM_unfreezeGC(state); } @@ -20,6 +21,41 @@ CValue cosmoB_print(CState *state, int nargs, CValue *args) { return cosmoV_newNil(); // print doesn't return any args } +CValue cosmoB_foreach(CState *state, int nargs, CValue *args) { + if (nargs != 2) { + cosmoV_error(state, "foreach() expected 2 parameters, got %d!", nargs); + return cosmoV_newNil(); + } + + if (!IS_DICT(args[0])) { + cosmoV_error(state, "foreach() expected first parameter to be , got %s!", cosmoV_typeStr(args[0])); + return cosmoV_newNil(); + } + + if (!IS_CALLABLE(args[1])) { + cosmoV_error(state, "foreach() expected second parameter to be callable, got %s!", cosmoV_typeStr(args[1])); + return cosmoV_newNil(); + } + + // loop through dictonary table, calling args[1] on active entries + CObjDict *dict = (CObjDict*)cosmoV_readObj(args[0]); + + for (int i = 0; i < dict->tbl.capacity; i++) { + CTableEntry *entry = &dict->tbl.table[i]; + + if (!IS_NIL(entry->key)) { + // push key & value, then call args[1] + cosmoV_pushValue(state, args[1]); + cosmoV_pushValue(state, entry->key); + cosmoV_pushValue(state, entry->val); + cosmoV_call(state, 2); + cosmoV_pop(state); // throw away the return value + } + } + + return cosmoV_newNil(); +} + CValue cosmoB_dsetProto(CState *state, int nargs, CValue *args) { if (nargs == 2) { CObjObject *obj = cosmoV_readObject(args[0]); // object to set proto too diff --git a/src/cbaselib.h b/src/cbaselib.h index f1b9ec0..45baa51 100644 --- a/src/cbaselib.h +++ b/src/cbaselib.h @@ -7,5 +7,6 @@ COSMO_API void cosmoB_loadLibrary(CState *state); COSMO_API void cosmoB_loadDebug(CState *state); COSMO_API CValue cosmoB_print(CState *state, int nargs, CValue *args); +COSMO_API CValue cosmoB_foreach(CState *state, int nargs, CValue *args); #endif \ No newline at end of file diff --git a/src/cobj.h b/src/cobj.h index 4de0f45..9fe8b6e 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -111,6 +111,11 @@ static inline bool isObjType(CValue val, CObjType type) { return IS_OBJ(val) && cosmoV_readObj(val)->type == type; } +// just protects against macro expansion +static inline bool IS_CALLABLE(CValue val) { + return IS_CLOSURE(val) || IS_CFUNCTION(val); +} + CObj *cosmoO_allocateBase(CState *state, size_t sz, CObjType type); void cosmoO_free(CState *state, CObj* obj);