Added '__count' metamethod to objects

This commit is contained in:
CPunch 2021-01-22 15:22:30 -06:00
parent 6b407534c0
commit 7c92749e0d
6 changed files with 51 additions and 8 deletions

View File

@ -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. 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 proto Test
function __init(self) 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 end
function print(self) function print(self)
@ -74,7 +75,8 @@ end
var objTest = Test() 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.print(objTest) // equivalent to invoking with ':' objTest.print(objTest) // equivalent to invoking with ':'
@ -93,6 +95,7 @@ that are called on special operators.
| __newindex | `(<object>, key, newValue)` | Called on new index using the '[] = ' operator | | __newindex | `(<object>, key, newValue)` | Called on new index using the '[] = ' operator |
| __index | `(<object>, key)` -> `value` | Called on index using the '[]' operator | | __index | `(<object>, key)` -> `value` | Called on index using the '[]' operator |
| __tostring | `(<object>)` -> `<string>` | Called when tostring() is called on an object | | __tostring | `(<object>)` -> `<string>` | Called when tostring() is called on an object |
| __count | `(<object>)` -> `<number>` | Called when object is used with the '#' count operator |
| __iter | `(<object>)` -> `<object>` | Called when used in a for-each loop with the 'in' operator | | __iter | `(<object>)` -> `<object>` | Called when used in a for-each loop with the 'in' operator |
| __next | `(<object>)` -> `...` | Called on each iteration in a for-each loop, return values are passed as parameters in the loop | | __next | `(<object>)` -> `...` | Called on each iteration in a for-each loop, return values are passed as parameters in the loop |
| __getter | `[<string> fieldName : <function> getterMethod]` | Indexed & called on field get using the '.' operator | | __getter | `[<string> fieldName : <function> getterMethod]` | Indexed & called on field get using the '.' operator |

View File

@ -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 <number>
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;
}
}
void printObject(CObj *o) { void printObject(CObj *o) {
switch (o->type) { switch (o->type) {
case COBJ_STRING: { case COBJ_STRING: {

View File

@ -195,5 +195,6 @@ const char *cosmoO_typeStr(CObj* obj);
CObjString *cosmoO_toString(CState *state, CObj *obj); CObjString *cosmoO_toString(CState *state, CObj *obj);
cosmo_Number cosmoO_toNumber(CState *state, CObj *obj); cosmo_Number cosmoO_toNumber(CState *state, CObj *obj);
int cosmoO_count(CState *state, CObj *obj);
#endif #endif

View File

@ -50,6 +50,7 @@ CState *cosmoV_newState() {
state->iStrings[ISTRING_TOSTRING] = cosmoO_copyString(state, "__tostring", 10); state->iStrings[ISTRING_TOSTRING] = cosmoO_copyString(state, "__tostring", 10);
state->iStrings[ISTRING_INDEX] = cosmoO_copyString(state, "__index", 7); state->iStrings[ISTRING_INDEX] = cosmoO_copyString(state, "__index", 7);
state->iStrings[ISTRING_NEWINDEX] = cosmoO_copyString(state, "__newindex", 10); state->iStrings[ISTRING_NEWINDEX] = cosmoO_copyString(state, "__newindex", 10);
state->iStrings[ISTRING_COUNT] = cosmoO_copyString(state, "__count", 7);
// getters/setters // getters/setters
state->iStrings[ISTRING_GETTER] = cosmoO_copyString(state, "__getter", 8); state->iStrings[ISTRING_GETTER] = cosmoO_copyString(state, "__getter", 8);

View File

@ -17,6 +17,7 @@ typedef enum IStringEnum {
ISTRING_TOSTRING, // __tostring ISTRING_TOSTRING, // __tostring
ISTRING_INDEX, // __index ISTRING_INDEX, // __index
ISTRING_NEWINDEX, // __newindex ISTRING_NEWINDEX, // __newindex
ISTRING_COUNT, // __count
ISTRING_GETTER, // __getter ISTRING_GETTER, // __getter
ISTRING_SETTER, // __setter ISTRING_SETTER, // __setter
ISTRING_ITER, // __iter ISTRING_ITER, // __iter

View File

@ -979,17 +979,18 @@ int cosmoV_execute(CState *state) {
} }
continue; 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); StkPtr temp = cosmoV_getTop(state, 0);
if (!IS_TABLE(*temp)) { if (!IS_OBJ(*temp)) {
cosmoV_error(state, "Expected table, got %s!", cosmoV_typeStr(*temp)); cosmoV_error(state, "Expected non-primitive, got %s!", cosmoV_typeStr(*temp));
return -1; return -1;
} }
CObjTable *tbl = (CObjTable*)cosmoV_readObj(*temp); int count = cosmoO_count(state, cosmoV_readObj(*temp));
cosmoV_pop(state); 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; continue;
} }
case OP_CONCAT: { case OP_CONCAT: {