mirror of
https://github.com/CPunch/Cosmo.git
synced 2024-12-22 22:40:03 +00:00
CObjMethod refactor
This commit is contained in:
parent
40ae495aaf
commit
08b6dcbf4c
@ -1,8 +1,15 @@
|
||||
-- makes a hundred thousand entries in the hashtable
|
||||
var test = {}
|
||||
class test
|
||||
function __init(self, x)
|
||||
self.x = x
|
||||
end
|
||||
|
||||
for (var i = 0; i < 100000; i=i+1) do
|
||||
test[i] = "" .. i*i
|
||||
function print(self)
|
||||
print(self.x)
|
||||
|
||||
return self.x
|
||||
end
|
||||
end
|
||||
|
||||
print(test[4]) -- should print '16'
|
||||
var t = test("hello")
|
||||
|
||||
print(t.print())
|
@ -4,7 +4,7 @@
|
||||
#include "cobj.h"
|
||||
#include "cmem.h"
|
||||
|
||||
void cosmoB_loadlibrary(CState *state) {
|
||||
void cosmoB_loadLibrary(CState *state) {
|
||||
cosmoM_freezeGC(state);
|
||||
cosmoV_register(state, "print", cosmoV_newObj(cosmoO_newCFunction(state, cosmoB_print)));
|
||||
cosmoM_unfreezeGC(state);
|
||||
@ -18,4 +18,28 @@ CValue cosmoB_print(CState *state, int nargs, CValue *args) {
|
||||
printf("\n");
|
||||
|
||||
return cosmoV_newNil(); // print doesn't return any args
|
||||
}
|
||||
|
||||
CValue cosmoB_dsetMeta(CState *state, int nargs, CValue *args) {
|
||||
if (nargs == 2) {
|
||||
CObjObject *obj = cosmoV_readObject(args[0]); // object to set meta too
|
||||
CObjObject *meta = cosmoV_readObject(args[1]);
|
||||
|
||||
obj->meta = meta; // boom done
|
||||
}
|
||||
|
||||
return cosmoV_newNil(); // nothing
|
||||
}
|
||||
CValue cosmoB_dgetMeta(CState *state, int nargs, CValue *args) {
|
||||
return cosmoV_newObj(cosmoV_readObject(args[0])->meta); // just return the meta
|
||||
}
|
||||
|
||||
void cosmoB_loadDebug(CState *state) {
|
||||
cosmoV_pushString(state, "getMeta");
|
||||
cosmoV_pushCFunction(state, cosmoB_dgetMeta);
|
||||
cosmoV_pushString(state, "setMeta");
|
||||
cosmoV_pushCFunction(state, cosmoB_dsetMeta);
|
||||
cosmoV_pushObject(state, 2);
|
||||
|
||||
state->metaObj = cosmoV_readObject(*cosmoV_pop(state));
|
||||
}
|
@ -3,7 +3,9 @@
|
||||
|
||||
#include "cstate.h"
|
||||
|
||||
COSMO_API void cosmoB_loadlibrary(CState *state);
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
@ -4,6 +4,7 @@
|
||||
#include "ctable.h"
|
||||
#include "cparse.h"
|
||||
#include "cobj.h"
|
||||
#include "cbaselib.h"
|
||||
|
||||
/*
|
||||
copy buffer to new larger buffer, and free the old buffer
|
||||
@ -213,6 +214,8 @@ void markRoots(CState *state) {
|
||||
for (int i = 0; i < INTERNALSTRING_MAX; i++)
|
||||
markObject(state, (CObj*)state->internalStrings[i]);
|
||||
|
||||
// mark our meta object
|
||||
markObject(state, (CObj*)state->metaObj);
|
||||
traceGrays(state);
|
||||
}
|
||||
|
||||
|
11
src/cobj.c
11
src/cobj.c
@ -94,7 +94,7 @@ bool cosmoO_equal(CObj* obj1, CObj* obj2) {
|
||||
|
||||
CObjObject *cosmoO_newObject(CState *state) {
|
||||
CObjObject *obj = (CObjObject*)cosmoO_allocateBase(state, sizeof(CObjObject), COBJ_OBJECT);
|
||||
obj->meta = NULL;
|
||||
obj->meta = state->metaObj;
|
||||
cosmoV_pushValue(state, cosmoV_newObj(obj)); // so out GC can keep track of it
|
||||
cosmoT_initTable(state, &obj->tbl, ARRAY_START);
|
||||
cosmoV_pop(state);
|
||||
@ -118,10 +118,19 @@ CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func) {
|
||||
return cfunc;
|
||||
}
|
||||
|
||||
CObjMethod *cosmoO_newCMethod(CState *state, CObjCFunction *func, CObjObject *obj) {
|
||||
CObjMethod *method = (CObjMethod*)cosmoO_allocateBase(state, sizeof(CObjMethod), COBJ_METHOD);
|
||||
method->cfunc = func;
|
||||
method->obj = obj;
|
||||
method->isCFunc = true;
|
||||
return method;
|
||||
}
|
||||
|
||||
CObjMethod *cosmoO_newMethod(CState *state, CObjClosure *func, CObjObject *obj) {
|
||||
CObjMethod *method = (CObjMethod*)cosmoO_allocateBase(state, sizeof(CObjMethod), COBJ_METHOD);
|
||||
method->closure = func;
|
||||
method->obj = obj;
|
||||
method->isCFunc = false;
|
||||
return method;
|
||||
}
|
||||
|
||||
|
19
src/cobj.h
19
src/cobj.h
@ -65,7 +65,11 @@ typedef struct CObjClosure {
|
||||
typedef struct CObjMethod {
|
||||
CommonHeader; // "is a " CObj
|
||||
CObjObject *obj; // obj this method is bound too
|
||||
CObjClosure *closure; // TODO: change this to a union to a pointer to a closure object or a c function object
|
||||
union {
|
||||
CObjClosure *closure;
|
||||
CObjCFunction *cfunc;
|
||||
};
|
||||
bool isCFunc;
|
||||
} CObjMethod;
|
||||
|
||||
typedef struct CObjUpval {
|
||||
@ -82,12 +86,12 @@ typedef struct CObjUpval {
|
||||
#define IS_METHOD(x) isObjType(x, COBJ_METHOD)
|
||||
#define IS_CLOSURE(x) isObjType(x, COBJ_CLOSURE)
|
||||
|
||||
#define cosmoV_readString(x) ((CObjString*)cosmoV_readObj(x))
|
||||
#define cosmoV_readObject(x) ((CObjObject*)cosmoV_readObj(x))
|
||||
#define cosmoV_readFunction(x) ((CObjFunction*)cosmoV_readObj(x))
|
||||
#define cosmoV_readCFunction(x) (((CObjCFunction*)cosmoV_readObj(x))->cfunc)
|
||||
#define cosmoV_readMethod(x) ((CObjMethod*)cosmoV_readObj(x))
|
||||
#define cosmoV_readClosure(x) ((CObjClosure*)cosmoV_readObj(x))
|
||||
#define cosmoV_readString(x) ((CObjString*)cosmoV_readObj((x)))
|
||||
#define cosmoV_readObject(x) ((CObjObject*)cosmoV_readObj((x)))
|
||||
#define cosmoV_readFunction(x) ((CObjFunction*)cosmoV_readObj((x)))
|
||||
#define cosmoV_readCFunction(x) (((CObjCFunction*)cosmoV_readObj((x)))->cfunc)
|
||||
#define cosmoV_readMethod(x) ((CObjMethod*)cosmoV_readObj((x)))
|
||||
#define cosmoV_readClosure(x) ((CObjClosure*)cosmoV_readObj((x)))
|
||||
|
||||
static inline bool isObjType(CValue val, CObjType type) {
|
||||
return IS_OBJ(val) && cosmoV_readObj(val)->type == type;
|
||||
@ -102,6 +106,7 @@ CObjObject *cosmoO_newObject(CState *state);
|
||||
CObjFunction *cosmoO_newFunction(CState *state);
|
||||
CObjCFunction *cosmoO_newCFunction(CState *state, CosmoCFunction func);
|
||||
CObjMethod *cosmoO_newMethod(CState *state, CObjClosure *func, CObjObject *obj);
|
||||
CObjMethod *cosmoO_newCMethod(CState *state, CObjCFunction *func, CObjObject *obj);
|
||||
CObjClosure *cosmoO_newClosure(CState *state, CObjFunction *func);
|
||||
CObjString *cosmoO_toString(CState *state, CObj *val);
|
||||
CObjUpval *cosmoO_newUpvalue(CState *state, CValue *val);
|
||||
|
@ -955,7 +955,7 @@ static void functionDeclaration(CParseState *pstate) {
|
||||
}
|
||||
|
||||
static void returnStatement(CParseState *pstate) {
|
||||
if (pstate->compiler->type != FTYPE_FUNCTION) {
|
||||
if (pstate->compiler->type != FTYPE_FUNCTION && pstate->compiler->type != FTYPE_METHOD) {
|
||||
error(pstate, "Expected 'return' in function!");
|
||||
return;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ CState *cosmoV_newState() {
|
||||
state->top = state->stack;
|
||||
state->frameCount = 0;
|
||||
state->openUpvalues = NULL;
|
||||
state->metaObj = NULL;
|
||||
|
||||
cosmoT_initTable(state, &state->strings, 8); // init string table
|
||||
cosmoT_initTable(state, &state->globals, 8); // init global table
|
||||
|
@ -38,6 +38,7 @@ typedef struct CState {
|
||||
int frameCount;
|
||||
|
||||
CObjString *internalStrings[INTERNALSTRING_MAX]; // strings used internally by the VM, eg. __init
|
||||
CObjObject *metaObj; // start met obj for all objects (NULL by default)
|
||||
} CState;
|
||||
|
||||
COSMO_API CState *cosmoV_newState();
|
||||
|
110
src/cvm.c
110
src/cvm.c
@ -137,6 +137,43 @@ bool call(CState *state, CObjClosure *closure, int args) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool callMethod(CState* state, CObjMethod *method, int args) {
|
||||
if (method->isCFunc) {
|
||||
StkPtr savedBase = state->top - args - 1;
|
||||
|
||||
cosmoM_freezeGC(state);
|
||||
CValue res = method->cfunc->cfunc(state, args+1, savedBase);
|
||||
cosmoM_unfreezeGC(state);
|
||||
|
||||
state->top = savedBase;
|
||||
cosmoV_pushValue(state, res);
|
||||
} else {
|
||||
CObjClosure *closure = method->closure;
|
||||
|
||||
StkPtr val = state->top - args - 1;
|
||||
|
||||
if (args+1 != closure->function->args) {
|
||||
runtimeError(state, "Expected %d parameters for %s, got %d!", closure->function->args, closure->function->name == NULL ? UNNAMEDCHUNK : closure->function->name->str, args+1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// load function into callframe
|
||||
pushCallFrame(state, closure, closure->function->args);
|
||||
|
||||
// execute
|
||||
if (!cosmoV_execute(state))
|
||||
return false;
|
||||
CValue* result = state->top - 1;
|
||||
|
||||
// pop the callframe and return result
|
||||
popCallFrame(state);
|
||||
state->top++;
|
||||
cosmoV_pushValue(state, *result); // and push return value
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// args = # of pass parameters
|
||||
COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
||||
StkPtr val = cosmoV_getTop(state, args); // function will always be right above the args
|
||||
@ -157,26 +194,7 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
||||
case COBJ_METHOD: {
|
||||
CObjMethod *method = (CObjMethod*)val->val.obj;
|
||||
*val = cosmoV_newObj(method->obj); // sets the object on the stack so the function can reference it in it's first argument
|
||||
|
||||
CObjClosure *closure = method->closure;
|
||||
|
||||
if (args+1 != closure->function->args) {
|
||||
runtimeError(state, "Expected %d parameters for %s, got %d!", closure->function->args, closure->function->name == NULL ? UNNAMEDCHUNK : closure->function->name->str, args+1);
|
||||
return COSMOVM_RUNTIME_ERR;
|
||||
}
|
||||
|
||||
// load function into callframe
|
||||
pushCallFrame(state, closure, closure->function->args);
|
||||
|
||||
// execute
|
||||
if (!cosmoV_execute(state))
|
||||
return COSMOVM_RUNTIME_ERR;
|
||||
CValue* result = state->top - 1;
|
||||
|
||||
// pop the callframe and return result
|
||||
popCallFrame(state);
|
||||
state->top++; // adjust stack back into place
|
||||
cosmoV_pushValue(state, *result); // and push return value
|
||||
callMethod(state, method, args);
|
||||
break;
|
||||
}
|
||||
case COBJ_OBJECT: {
|
||||
@ -187,25 +205,9 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
||||
CValue ret;
|
||||
|
||||
// check if they defined an initalizer
|
||||
if (cosmoO_getObject(state, metaObj, cosmoV_newObj(state->internalStrings[INTERNALSTRING_INIT]), &ret) && IS_CLOSURE(ret)) {
|
||||
CObjClosure *closure = cosmoV_readClosure(ret);
|
||||
|
||||
if (args+1 != closure->function->args) {
|
||||
runtimeError(state, "Expected %d parameters for %s, got %d!", closure->function->args, closure->function->name == NULL ? UNNAMEDCHUNK : closure->function->name->str, args+1);
|
||||
return COSMOVM_RUNTIME_ERR;
|
||||
}
|
||||
|
||||
// load function into callframe
|
||||
pushCallFrame(state, closure, closure->function->args);
|
||||
|
||||
// execute
|
||||
if (!cosmoV_execute(state))
|
||||
return COSMOVM_RUNTIME_ERR;
|
||||
|
||||
// we throw away the return result, it's ignored
|
||||
// pop the callframe and return the new object :)
|
||||
popCallFrame(state);
|
||||
state->top++; // adjust stack back into place
|
||||
if (cosmoV_getObject(state, metaObj, cosmoV_newObj(state->internalStrings[INTERNALSTRING_INIT]), &ret) && IS_METHOD(ret)) {
|
||||
callMethod(state, cosmoV_readMethod(ret), args);
|
||||
cosmoV_pop(state);
|
||||
} else {
|
||||
// no default initalizer
|
||||
if (args != 0) {
|
||||
@ -221,13 +223,13 @@ COSMOVMRESULT cosmoV_call(CState *state, int args) {
|
||||
case COBJ_CFUNCTION: {
|
||||
// it's a C function, so call it
|
||||
CosmoCFunction cfunc = ((CObjCFunction*)(val->val.obj))->cfunc;
|
||||
CValue *savedBase = state->top - args - 1;
|
||||
CValue *savedBase = state->top - args;
|
||||
|
||||
cosmoM_freezeGC(state); // we don't want a GC event during c api because we don't actually trust the user to know how to evade the GC
|
||||
CValue res = cfunc(state, args, state->top - args);
|
||||
CValue res = cfunc(state, args, savedBase);
|
||||
cosmoM_unfreezeGC(state);
|
||||
|
||||
state->top = savedBase;
|
||||
state->top = savedBase - 1;
|
||||
cosmoV_pushValue(state, res);
|
||||
break;
|
||||
}
|
||||
@ -262,6 +264,24 @@ COSMO_API void cosmoV_pushObject(CState *state, int pairs) {
|
||||
cosmoV_pushValue(state, cosmoV_newObj(newObj));
|
||||
}
|
||||
|
||||
COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, CValue *val) {
|
||||
if (cosmoO_getObject(state, object, key, val)) {
|
||||
if (val->type == COSMO_TOBJ ) {
|
||||
if (val->val.obj->type == COBJ_CLOSURE) { // is it a function? if so, make it a method to the current object
|
||||
CObjMethod *method = cosmoO_newMethod(state, (CObjClosure*)val->val.obj, object);
|
||||
*val = cosmoV_newObj(method);
|
||||
} else if (val->val.obj->type == COBJ_CFUNCTION) {
|
||||
CObjMethod *method = cosmoO_newCMethod(state, (CObjCFunction*)val->val.obj, object);
|
||||
*val = cosmoV_newObj(method);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define BINARYOP(typeConst, op) \
|
||||
StkPtr valA = cosmoV_getTop(state, 1); \
|
||||
StkPtr valB = cosmoV_getTop(state, 0); \
|
||||
@ -403,11 +423,7 @@ bool cosmoV_execute(CState *state) {
|
||||
CObjObject *object = (CObjObject*)temp->val.obj;
|
||||
CValue val; // to hold our value
|
||||
|
||||
cosmoO_getObject(state, object, *key, &val);
|
||||
if (IS_CLOSURE(val)) { // is it a function? if so, make it a method to the current object
|
||||
CObjMethod *method = cosmoO_newMethod(state, cosmoV_readClosure(val), object);
|
||||
val = cosmoV_newObj(method);
|
||||
}
|
||||
cosmoV_getObject(state, object, *key, &val);
|
||||
cosmoV_setTop(state, 2); // pops the object & the key
|
||||
cosmoV_pushValue(state, val); // pushes the field result
|
||||
break;
|
||||
|
@ -15,6 +15,7 @@ typedef enum {
|
||||
// args = # of pass parameters, nresults = # of expected results
|
||||
COSMO_API COSMOVMRESULT cosmoV_call(CState *state, int args);
|
||||
COSMO_API void cosmoV_pushObject(CState *state, int pairs);
|
||||
COSMO_API bool cosmoV_getObject(CState *state, CObjObject *object, CValue key, CValue *val);
|
||||
|
||||
// nice to have wrappers
|
||||
|
||||
|
@ -48,7 +48,8 @@ static void repl() {
|
||||
_ACTIVE = true;
|
||||
|
||||
CState *state = cosmoV_newState();
|
||||
cosmoB_loadlibrary(state);
|
||||
cosmoB_loadLibrary(state);
|
||||
cosmoB_loadDebug(state);
|
||||
|
||||
// TODO: there's gotta be a better way to do this
|
||||
cosmoV_register(state, "quit", cosmoV_newObj(cosmoO_newCFunction(state, cosmoB_quitRepl)));
|
||||
@ -103,7 +104,7 @@ static char *readFile(const char* path) {
|
||||
static void runFile(const char* fileName) {
|
||||
char* script = readFile(fileName);
|
||||
CState *state = cosmoV_newState();
|
||||
cosmoB_loadlibrary(state);
|
||||
cosmoB_loadLibrary(state);
|
||||
|
||||
cosmoV_register(state, "input", cosmoV_newObj(cosmoO_newCFunction(state, cosmoB_input)));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user