diff --git a/docs/objects.md b/docs/objects.md index 170ed0c..7f4e4d5 100644 --- a/docs/objects.md +++ b/docs/objects.md @@ -1,4 +1,4 @@ -# Prototype Objects +# Objects & Protos Cosmo supports an eccentric form of Object-Oriented Programming through the use of Objects and Proto-Objects. Under the hood, these are the same datatype, however they can be chained to describe behaviors in relation to other Objects, operators, and provide stateful functions. @@ -64,7 +64,8 @@ Objects have two main ways of being declared, first was just shown in the above ``` proto Test function __init(self) - // __init is required for an object to be instantiated, the 'self' passed is the newly allocated object with it's proto already set to + // __init is required for an object to be instantiated, the 'self' passed is the + // newly allocated object with it's proto already set end function print(self) @@ -74,7 +75,8 @@ end var objTest = Test() -// the ':' operator is used to invoke a method. if the '.' operator is used instead, the raw closure will be given meaning the 'self' parameter won't be populated +// the ':' operator is used to invoke a method. if the '.' operator is used instead, the +// raw closure will be given meaning the 'self' parameter won't be populated objTest:print() objTest.print(objTest) // equivalent to invoking with ':' @@ -93,6 +95,7 @@ that are called on special operators. | __newindex | `(, key, newValue)` | Called on new index using the '[] = ' operator | | __index | `(, key)` -> `value` | Called on index using the '[]' operator | | __tostring | `()` -> `` | Called when tostring() is called on an object | +| __count | `()` -> `` | Called when object is used with the '#' count operator | | __iter | `()` -> `` | Called when used in a for-each loop with the 'in' operator | | __next | `()` -> `...` | Called on each iteration in a for-each loop, return values are passed as parameters in the loop | | __getter | `[ fieldName : getterMethod]` | Indexed & called on field get using the '.' operator | diff --git a/src/cobj.c b/src/cobj.c index 9d17600..446b183 100644 --- a/src/cobj.c +++ b/src/cobj.c @@ -472,6 +472,42 @@ cosmo_Number cosmoO_toNumber(CState *state, CObj *obj) { } } +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_pushValue(state, cosmoV_newObj(obj)); + if (!cosmoV_call(state, 1, 1) != COSMOVM_OK) // call ret, we expect 1 return value of type + return 0; + + StkPtr ret = cosmoV_getTop(state, 0); + if (!IS_NUMBER(*ret)) { + cosmoV_error(state, "__count expected to return , 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; + } +} + void printObject(CObj *o) { switch (o->type) { case COBJ_STRING: { diff --git a/src/cobj.h b/src/cobj.h index 195cad5..f3d80ca 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -195,5 +195,6 @@ const char *cosmoO_typeStr(CObj* obj); CObjString *cosmoO_toString(CState *state, CObj *obj); cosmo_Number cosmoO_toNumber(CState *state, CObj *obj); +int cosmoO_count(CState *state, CObj *obj); #endif diff --git a/src/cstate.c b/src/cstate.c index 3f32e33..40367a5 100644 --- a/src/cstate.c +++ b/src/cstate.c @@ -50,6 +50,7 @@ CState *cosmoV_newState() { state->iStrings[ISTRING_TOSTRING] = cosmoO_copyString(state, "__tostring", 10); state->iStrings[ISTRING_INDEX] = cosmoO_copyString(state, "__index", 7); state->iStrings[ISTRING_NEWINDEX] = cosmoO_copyString(state, "__newindex", 10); + state->iStrings[ISTRING_COUNT] = cosmoO_copyString(state, "__count", 7); // getters/setters state->iStrings[ISTRING_GETTER] = cosmoO_copyString(state, "__getter", 8); diff --git a/src/cstate.h b/src/cstate.h index c24fc95..82f1797 100644 --- a/src/cstate.h +++ b/src/cstate.h @@ -17,6 +17,7 @@ typedef enum IStringEnum { ISTRING_TOSTRING, // __tostring ISTRING_INDEX, // __index ISTRING_NEWINDEX, // __newindex + ISTRING_COUNT, // __count ISTRING_GETTER, // __getter ISTRING_SETTER, // __setter ISTRING_ITER, // __iter diff --git a/src/cvm.c b/src/cvm.c index bf212cb..9bc118a 100644 --- a/src/cvm.c +++ b/src/cvm.c @@ -979,17 +979,18 @@ int cosmoV_execute(CState *state) { } continue; } - case OP_COUNT: { // pop 1 value off the stack & if it's a table return the amount of active entries it has + case OP_COUNT: { StkPtr temp = cosmoV_getTop(state, 0); - if (!IS_TABLE(*temp)) { - cosmoV_error(state, "Expected table, got %s!", cosmoV_typeStr(*temp)); + if (!IS_OBJ(*temp)) { + cosmoV_error(state, "Expected non-primitive, got %s!", cosmoV_typeStr(*temp)); return -1; } - CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp); + int count = cosmoO_count(state, cosmoV_readObj(*temp)); cosmoV_pop(state); - cosmoV_pushNumber(state, cosmoT_count(&tbl->tbl)); // pushes the count onto the stack + + cosmoV_pushNumber(state, count); // pushes the count onto the stack continue; } case OP_CONCAT: {