From 204bec3d0abf373402e8f211234cbb63b13ddc72 Mon Sep 17 00:00:00 2001 From: CPunch Date: Mon, 16 Nov 2020 19:58:16 -0600 Subject: [PATCH] added IStrings, added __index functionality --- examples/test.cosmo | 30 +++++++++--------------------- src/cmem.c | 4 ++-- src/cobj.c | 34 ++++++++++++++++++++++++++++++++-- src/cobj.h | 10 ++++++++++ src/cosmo.h | 1 + src/cstate.c | 11 ++++++----- src/cstate.h | 13 +++++++------ src/cvm.c | 2 +- 8 files changed, 68 insertions(+), 37 deletions(-) diff --git a/examples/test.cosmo b/examples/test.cosmo index ba09f7b..85431ec 100644 --- a/examples/test.cosmo +++ b/examples/test.cosmo @@ -1,26 +1,14 @@ -class test - function __init(self, str) - self.hello = str - end +-- crafts a dummy class +class test end - function print(self, i) - var str = self.hello +-- instance of test +var obj = test() - for (var x = i; x > 0; x=x-1) do - str = str .. "!" - end - - print(str) +test.__index = function(self, key) + print("__index called!") + if (key == "lol") then + return 9001 end end -var obj = test("Hello world") -for (var i = 1; i <= 1; i=i+1) do - obj.print(i) -end - -test.debug = function(self) - print("hi from " .. self) -end - -obj.debug() \ No newline at end of file +print(obj["lol"]) -- should print 9001? \ No newline at end of file diff --git a/src/cmem.c b/src/cmem.c index db4a6fb..c240906 100644 --- a/src/cmem.c +++ b/src/cmem.c @@ -211,8 +211,8 @@ void markRoots(CState *state) { markTable(state, &state->globals); // mark all internal strings - for (int i = 0; i < INTERNALSTRING_MAX; i++) - markObject(state, (CObj*)state->internalStrings[i]); + for (int i = 0; i < ISTRING_MAX; i++) + markObject(state, (CObj*)state->iStrings[i]); // mark our proto object markObject(state, (CObj*)state->protoObj); diff --git a/src/cobj.c b/src/cobj.c index fe55a13..7439063 100644 --- a/src/cobj.c +++ b/src/cobj.c @@ -2,6 +2,7 @@ #include "ctable.h" #include "cobj.h" #include "cmem.h" +#include "cvm.h" #include @@ -95,6 +96,7 @@ bool cosmoO_equal(CObj* obj1, CObj* obj2) { CObjObject *cosmoO_newObject(CState *state) { CObjObject *obj = (CObjObject*)cosmoO_allocateBase(state, sizeof(CObjObject), COBJ_OBJECT); obj->proto = state->protoObj; + obj->istringFlags = 0; obj->user = NULL; // reserved for C API cosmoV_pushValue(state, cosmoV_newObj(obj)); // so our GC can keep track of it cosmoT_initTable(state, &obj->tbl, ARRAY_START); @@ -204,18 +206,46 @@ 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) && object->proto != NULL) { // if the field doesn't exist in the object, check the proto - return cosmoO_getObject(state, object->proto, key, 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 __index, if that exists, call it + if (cosmoO_getIString(state, object->proto, ISTRING_INDEX, val)) { + cosmoV_pushValue(state, *val); // push function + cosmoV_pushValue(state, cosmoV_newObj(object)); // push object + cosmoV_pushValue(state, key); // push key + cosmoV_call(state, 2); // call the function with the 2 arguments + *val = *cosmoV_pop(state); // set value to the return value of __index + return true; + } + + return cosmoO_getObject(state, object->proto, key, val); + } + + return false; // no protoobject to check against } return true; } void cosmoO_setObject(CState *state, CObjObject *object, CValue key, CValue val) { + object->istringFlags = 0; // reset cache CValue *newVal = cosmoT_insert(state, &object->tbl, key); *newVal = val; } +bool cosmoO_getIString(CState *state, CObjObject *object, int flag, CValue *val) { + if (readFlag(object->istringFlags, flag)) + return false; // it's been cached as bad + + if (!cosmoO_getObject(state, object, cosmoV_newObj(state->iStrings[flag]), val)) { + // mark it bad! + setFlagOn(object->istringFlags, flag); + return false; + } + + return true; // :) +} + CObjString *cosmoO_toString(CState *state, CObj *obj) { switch (obj->type) { case COBJ_STRING: { diff --git a/src/cobj.h b/src/cobj.h index 4aaf004..5d0a1a1 100644 --- a/src/cobj.h +++ b/src/cobj.h @@ -2,11 +2,13 @@ #define COBJ_H #include "cosmo.h" +#include "cstate.h" #include "cchunk.h" #include "cvalue.h" #include "ctable.h" typedef struct CState CState; +typedef uint32_t cosmo_Flag; typedef enum { COBJ_STRING, @@ -20,6 +22,8 @@ typedef enum { } CObjType; #define CommonHeader CObj _obj; +#define readFlag(x, flag) (x & (1u << flag)) +#define setFlagOn(x, flag) (x |= (1u << flag)) typedef CValue (*CosmoCFunction)(CState *state, int argCount, CValue *args); @@ -38,6 +42,7 @@ typedef struct CObjString { typedef struct CObjObject { CommonHeader; // "is a" CObj + cosmo_Flag istringFlags; // enables us to have a much faster lookup for reserved IStrings (like __init, __index, etc.) CTable tbl; void *user; // userdata (NULL by default) struct CObjObject *proto; // protoobject, describes the behavior of the object @@ -80,6 +85,8 @@ typedef struct CObjUpval { struct CObjUpval *next; } CObjUpval; +#undef CommonHeader + #define IS_STRING(x) isObjType(x, COBJ_STRING) #define IS_TABLE(x) isObjType(x, COBJ_OBJECT) #define IS_FUNCTION(x) isObjType(x, COBJ_FUNCTION) @@ -115,6 +122,9 @@ CObjUpval *cosmoO_newUpvalue(CState *state, CValue *val); bool cosmoO_getObject(CState *state, CObjObject *object, CValue key, CValue *val); void cosmoO_setObject(CState *state, CObjObject *object, CValue key, CValue val); +// internal string +bool cosmoO_getIString(CState *state, CObjObject *object, int flag, CValue *val); + // copies the *str buffer to the heap and returns a CObjString struct which is also on the heap CObjString *cosmoO_copyString(CState *state, const char *str, size_t sz); // pass an already allocated str buffer! diff --git a/src/cosmo.h b/src/cosmo.h index 8533b76..249abab 100644 --- a/src/cosmo.h +++ b/src/cosmo.h @@ -19,6 +19,7 @@ typedef struct CObjUpval CObjUpval; typedef struct CObjFunction CObjFunction; typedef struct CObjCFunction CObjCFunction; typedef struct CObjMethod CObjMethod; +typedef struct CObjObject CObjObject; typedef struct CObjClass CObjClass; typedef struct CObjClosure CObjClosure; diff --git a/src/cstate.c b/src/cstate.c index 306c100..7825bbd 100644 --- a/src/cstate.c +++ b/src/cstate.c @@ -36,11 +36,12 @@ CState *cosmoV_newState() { cosmoT_initTable(state, &state->globals, 8); // init global table // first, set all strings to NULL so our GC doesn't read garbage data - for (int i = 0; i < INTERNALSTRING_MAX; i++) - state->internalStrings[i] = NULL; + for (int i = 0; i < ISTRING_MAX; i++) + state->iStrings[i] = NULL; // setup all strings used by the VM - state->internalStrings[INTERNALSTRING_INIT] = cosmoO_copyString(state, "__init", 6); + state->iStrings[ISTRING_INIT] = cosmoO_copyString(state, "__init", 6); + state->iStrings[ISTRING_INDEX] = cosmoO_copyString(state, "__index", 7); return state; } @@ -57,8 +58,8 @@ void cosmoV_freeState(CState *state) { } // mark our internal VM strings NULL - for (int i = 0; i < INTERNALSTRING_MAX; i++) - state->internalStrings[i] = NULL; + for (int i = 0; i < ISTRING_MAX; i++) + state->iStrings[i] = NULL; // free our string & global table (the string table includes the internal VM strings) cosmoT_clearTable(state, &state->strings); diff --git a/src/cstate.h b/src/cstate.h index 49fc2e2..fd2c541 100644 --- a/src/cstate.h +++ b/src/cstate.h @@ -12,11 +12,12 @@ typedef struct CCallFrame { CValue* base; } CCallFrame; -typedef enum { - INTERNALSTRING_INIT, // __init - INTERNALSTRING_EQUAL, // __equal - INTERNALSTRING_MAX -} InternalStringEnum; +typedef enum IStringEnum { + ISTRING_INIT, // __init + ISTRING_EQUAL, // __equal + ISTRING_INDEX, + ISTRING_MAX +} IStringEnum; typedef struct CState { bool panic; @@ -37,7 +38,7 @@ typedef struct CState { CCallFrame callFrame[FRAME_MAX]; // call frames int frameCount; - CObjString *internalStrings[INTERNALSTRING_MAX]; // strings used internally by the VM, eg. __init + CObjString *iStrings[ISTRING_MAX]; // strings used internally by the VM, eg. __init, __index & friends CObjObject *protoObj; // start met obj for all objects (NULL by default) } CState; diff --git a/src/cvm.c b/src/cvm.c index 155c1bf..9e19bfc 100644 --- a/src/cvm.c +++ b/src/cvm.c @@ -191,7 +191,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) { CValue ret; // check if they defined an initalizer - if (cosmoV_getObject(state, protoObj, cosmoV_newObj(state->internalStrings[INTERNALSTRING_INIT]), &ret) && IS_METHOD(ret)) { + if (cosmoV_getObject(state, protoObj, cosmoV_newObj(state->iStrings[ISTRING_INIT]), &ret) && IS_METHOD(ret)) { callMethod(state, cosmoV_readMethod(ret), args); cosmoV_pop(state); } else {