From d00b803e6f0cf09ced38b6f584556f695cde9643 Mon Sep 17 00:00:00 2001 From: CPunch Date: Sun, 6 Dec 2020 14:11:33 -0600 Subject: [PATCH] added __setter and __getter --- src/cbaselib.c | 18 ++++++++++++++---- src/cobj.c | 43 ++++++++++++++++++++++++++++++++----------- src/cobj.h | 2 +- src/cstate.c | 4 ++++ src/cstate.h | 2 ++ 5 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/cbaselib.c b/src/cbaselib.c index 171c47d..1f38d09 100644 --- a/src/cbaselib.c +++ b/src/cbaselib.c @@ -42,14 +42,24 @@ CValue cosmoB_dgetProto(CState *state, int nargs, CValue *args) { } void cosmoB_loadDebug(CState *state) { - cosmoV_pushString(state, "getProto"); // key + // make __getter object for debug proto + cosmoV_pushString(state, "__getter"); + + // key & value pair + cosmoV_pushString(state, "__proto"); // key cosmoV_pushCFunction(state, cosmoB_dgetProto); // value - // another key & value - cosmoV_pushString(state, "setProto"); + cosmoV_makeObject(state, 1); + + // make __setter object + cosmoV_pushString(state, "__setter"); + + cosmoV_pushString(state, "__proto"); cosmoV_pushCFunction(state, cosmoB_dsetProto); - // we call makeObject leting it know there are 2 sets of key & value pairs on the stack (4 values total) + cosmoV_makeObject(state, 1); + + // we call makeObject leting it know there are 2 sets of key & value pairs on the stack cosmoV_makeObject(state, 2); // set debug proto to the debug object diff --git a/src/cobj.c b/src/cobj.c index 8daa5ba..dc3ad72 100644 --- a/src/cobj.c +++ b/src/cobj.c @@ -206,10 +206,19 @@ CObjString *cosmoO_allocateString(CState *state, const char *str, size_t sz, uin bool cosmoO_getObject(CState *state, CObjObject *object, CValue key, CValue *val) { if (!cosmoT_get(&object->tbl, key, val)) { // if the field doesn't exist in the object, check the proto if (object->proto != NULL) { // sanity check - // first though, check for a member of the proto object, if it fails then lookup __index + // first though, check for a member of the proto object, if it fails then lookup __getters if (cosmoO_getObject(state, object->proto, key, val)) return true; + // if this fails or the key isn't in that table then we default to __index + if (cosmoO_getIString(state, object->proto, ISTRING_GETTER, val) && IS_OBJECT(*val) && cosmoO_getObject(state, cosmoV_readObject(*val), key, val)) { + cosmoV_pushValue(state, *val); // push function + cosmoV_pushValue(state, cosmoV_newObj(object)); // push object + cosmoV_call(state, 1); // call the function with the 1 argument + *val = *cosmoV_pop(state); // set value to the return value of __index + return true; + } + // then check for __index, if that exists, call it if (cosmoO_getIString(state, object->proto, ISTRING_INDEX, val)) { cosmoV_pushValue(state, *val); // push function @@ -229,16 +238,28 @@ bool cosmoO_getObject(CState *state, CObjObject *object, CValue key, CValue *val void cosmoO_setObject(CState *state, CObjObject *object, CValue key, CValue val) { CValue ret; - - // first check for __newindex in the prototype - if (object->proto != NULL && cosmoO_getIString(state, object->proto, ISTRING_NEWINDEX, &ret)) { - cosmoV_pushValue(state, ret); // push function - cosmoV_pushValue(state, cosmoV_newObj(object)); // push object - cosmoV_pushValue(state, key); // push key & value pair - cosmoV_pushValue(state, val); - cosmoV_call(state, 3); - cosmoV_pop(state); // pop return value - return; + + // if there's a prototype, check for the tag methods! + if (object->proto != NULL) { + // first check for __setters + if (cosmoO_getIString(state, object->proto, ISTRING_SETTER, &ret) && IS_OBJECT(ret) && cosmoO_getObject(state, cosmoV_readObject(ret), key, &ret)) { + cosmoV_pushValue(state, ret); // push function + cosmoV_pushValue(state, cosmoV_newObj(object)); // push object + cosmoV_pushValue(state, val); // push new value + cosmoV_call(state, 2); + cosmoV_pop(state); // pop return value + } + + // then check for __newindex in the prototype + if (cosmoO_getIString(state, object->proto, ISTRING_NEWINDEX, &ret)) { + cosmoV_pushValue(state, ret); // push function + cosmoV_pushValue(state, cosmoV_newObj(object)); // push object + cosmoV_pushValue(state, key); // push key & value pair + cosmoV_pushValue(state, val); + cosmoV_call(state, 3); + cosmoV_pop(state); // pop return value + return; + } } object->istringFlags = 0; // reset cache diff --git a/src/cobj.h b/src/cobj.h index b5905ef..3f7a25f 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -84,7 +84,7 @@ typedef struct CObjUpval { #undef CommonHeader #define IS_STRING(x) isObjType(x, COBJ_STRING) -#define IS_TABLE(x) isObjType(x, COBJ_OBJECT) +#define IS_OBJECT(x) isObjType(x, COBJ_OBJECT) #define IS_FUNCTION(x) isObjType(x, COBJ_FUNCTION) #define IS_CFUNCTION(x) isObjType(x, COBJ_CFUNCTION) #define IS_METHOD(x) isObjType(x, COBJ_METHOD) diff --git a/src/cstate.c b/src/cstate.c index 5c8c647..e1fa1de 100644 --- a/src/cstate.c +++ b/src/cstate.c @@ -44,6 +44,10 @@ CState *cosmoV_newState() { state->iStrings[ISTRING_INDEX] = cosmoO_copyString(state, "__index", 7); state->iStrings[ISTRING_NEWINDEX] = cosmoO_copyString(state, "__newindex", 10); + // getters/setters + state->iStrings[ISTRING_GETTER] = cosmoO_copyString(state, "__getter", 8); + state->iStrings[ISTRING_SETTER] = cosmoO_copyString(state, "__setter", 8); + return state; } diff --git a/src/cstate.h b/src/cstate.h index 7dc7caf..ef55ede 100644 --- a/src/cstate.h +++ b/src/cstate.h @@ -17,6 +17,8 @@ typedef enum IStringEnum { ISTRING_EQUAL, // __equal ISTRING_INDEX, // __index ISTRING_NEWINDEX, // __newindex + ISTRING_GETTER, // __getter + ISTRING_SETTER, // __setter ISTRING_MAX } IStringEnum;