mirror of
https://github.com/NeoFlock/neonucleus.git
synced 2026-02-15 04:03:49 +01:00
components
This commit is contained in:
parent
c0ce5bad26
commit
d0450c067b
@ -3,6 +3,22 @@
|
|||||||
// it is simply just to test stuff and showcase the API.
|
// it is simply just to test stuff and showcase the API.
|
||||||
|
|
||||||
#include "neonucleus.h"
|
#include "neonucleus.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static nn_Exit sandbox_handler(nn_ComponentRequest *req) {
|
||||||
|
switch(req->action) {
|
||||||
|
case NN_COMP_INIT:
|
||||||
|
return NN_OK;
|
||||||
|
case NN_COMP_DEINIT:
|
||||||
|
return NN_OK;
|
||||||
|
case NN_COMP_CALL:
|
||||||
|
return NN_OK;
|
||||||
|
case NN_COMP_ENABLED:
|
||||||
|
req->methodEnabled = true; // all methods always enabled
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
nn_Context ctx;
|
nn_Context ctx;
|
||||||
@ -15,13 +31,19 @@ int main() {
|
|||||||
{"log", "log(msg: string) - Log to stdout", true},
|
{"log", "log(msg: string) - Log to stdout", true},
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
nn_ComponentType *ctype = nn_createComponentType(u, "sandbox", NULL, sandboxMethods, NULL);
|
nn_ComponentType *ctype = nn_createComponentType(u, "sandbox", NULL, sandboxMethods, sandbox_handler);
|
||||||
|
|
||||||
nn_Computer *c = nn_createComputer(u, NULL, "computer0", 8 * NN_MiB, 256, 256);
|
nn_Computer *c = nn_createComputer(u, NULL, "computer0", 8 * NN_MiB, 256, 256);
|
||||||
|
|
||||||
|
nn_addComponent(c, ctype, "sandbox", -1, NULL);
|
||||||
|
|
||||||
|
printf("Component added: %s\n", nn_hasComponent(c, "sandbox") ? "TRUE" : "FALSE");
|
||||||
|
printf("Method active: %s\n", nn_hasMethod(c, "sandbox", "log") ? "TRUE" : "FALSE");
|
||||||
|
printf("Incorrect method active: %s\n", nn_hasMethod(c, "sandbox", "notlog") ? "TRUE" : "FALSE");
|
||||||
|
|
||||||
cleanup:;
|
cleanup:;
|
||||||
nn_destroyComponentType(ctype);
|
|
||||||
nn_destroyComputer(c);
|
nn_destroyComputer(c);
|
||||||
|
nn_destroyComponentType(ctype);
|
||||||
// rip the universe
|
// rip the universe
|
||||||
nn_destroyUniverse(u);
|
nn_destroyUniverse(u);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -13,27 +13,9 @@
|
|||||||
// Based off https://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
|
// Based off https://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
|
||||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||||
//define something for Windows (32-bit and 64-bit, this part is common)
|
//define something for Windows (32-bit and 64-bit, this part is common)
|
||||||
#ifdef _WIN64
|
#define NN_WINDOWS
|
||||||
#define NN_WINDOWS
|
|
||||||
#else
|
|
||||||
#error "Windows 32-bit is not supported"
|
|
||||||
#endif
|
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
#include <TargetConditionals.h>
|
#define NN_MACOS
|
||||||
#if TARGET_IPHONE_SIMULATOR
|
|
||||||
#error "iPhone Emulators are not supported"
|
|
||||||
#elif TARGET_OS_MACCATALYST
|
|
||||||
// I guess?
|
|
||||||
#define NN_MACOS
|
|
||||||
#elif TARGET_OS_IPHONE
|
|
||||||
#error "iPhone are not supported"
|
|
||||||
#elif TARGET_OS_MAC
|
|
||||||
#define NN_MACOS
|
|
||||||
#else
|
|
||||||
#error "Unknown Apple platform"
|
|
||||||
#endif
|
|
||||||
#elif __ANDROID__
|
|
||||||
#error "Android is not supported"
|
|
||||||
#elif __linux__
|
#elif __linux__
|
||||||
#define NN_LINUX
|
#define NN_LINUX
|
||||||
#endif
|
#endif
|
||||||
@ -168,7 +150,7 @@ void *nn_aralloc(nn_Arena *arena, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(arena->nextCap < size) arena->nextCap *= 2;
|
while(arena->nextCap <= size) arena->nextCap *= 2;
|
||||||
|
|
||||||
nn_ArenaBlock *newBlock = nn_arallocblock(&arena->ctx, arena->nextCap);
|
nn_ArenaBlock *newBlock = nn_arallocblock(&arena->ctx, arena->nextCap);
|
||||||
if(newBlock == NULL) {
|
if(newBlock == NULL) {
|
||||||
@ -397,8 +379,10 @@ typedef enum nn_BuiltinComponent {
|
|||||||
|
|
||||||
typedef struct nn_ComponentType {
|
typedef struct nn_ComponentType {
|
||||||
nn_Universe *universe;
|
nn_Universe *universe;
|
||||||
|
void *userdata;
|
||||||
nn_Arena arena;
|
nn_Arena arena;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
nn_ComponentHandler *handler;
|
||||||
// NULL-terminated
|
// NULL-terminated
|
||||||
nn_ComponentMethod *methods;
|
nn_ComponentMethod *methods;
|
||||||
size_t methodCount;
|
size_t methodCount;
|
||||||
@ -412,8 +396,9 @@ typedef struct nn_Universe {
|
|||||||
typedef struct nn_Component {
|
typedef struct nn_Component {
|
||||||
char *address;
|
char *address;
|
||||||
nn_ComponentType *ctype;
|
nn_ComponentType *ctype;
|
||||||
size_t slot;
|
int slot;
|
||||||
void *userdata;
|
void *userdata;
|
||||||
|
void *state;
|
||||||
} nn_Component;
|
} nn_Component;
|
||||||
|
|
||||||
// the values
|
// the values
|
||||||
@ -496,6 +481,8 @@ nn_ComponentType *nn_createComponentType(nn_Universe *universe, const char *name
|
|||||||
nn_ComponentType *ctype = nn_alloc(ctx, sizeof(nn_ComponentType));
|
nn_ComponentType *ctype = nn_alloc(ctx, sizeof(nn_ComponentType));
|
||||||
if(ctype == NULL) return NULL;
|
if(ctype == NULL) return NULL;
|
||||||
ctype->universe = universe;
|
ctype->universe = universe;
|
||||||
|
ctype->userdata = userdata;
|
||||||
|
ctype->handler = handler;
|
||||||
|
|
||||||
nn_Arena *arena = &ctype->arena;
|
nn_Arena *arena = &ctype->arena;
|
||||||
nn_arinit(arena, ctx);
|
nn_arinit(arena, ctx);
|
||||||
@ -586,10 +573,13 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nn_dropValue(nn_Value val);
|
||||||
|
static void nn_dropComponent(nn_Computer *computer, nn_Component c);
|
||||||
|
|
||||||
void nn_destroyComputer(nn_Computer *computer) {
|
void nn_destroyComputer(nn_Computer *computer) {
|
||||||
nn_Context *ctx = &computer->universe->ctx;
|
nn_Context *ctx = &computer->universe->ctx;
|
||||||
|
|
||||||
if(computer->arch.name != NULL) {
|
if(computer->arch.name != NULL && computer->archState != NULL) {
|
||||||
nn_ArchitectureRequest req;
|
nn_ArchitectureRequest req;
|
||||||
req.computer = computer;
|
req.computer = computer;
|
||||||
req.globalState = computer->arch.state;
|
req.globalState = computer->arch.state;
|
||||||
@ -598,6 +588,13 @@ void nn_destroyComputer(nn_Computer *computer) {
|
|||||||
computer->arch.handler(&req);
|
computer->arch.handler(&req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < computer->stackSize; i++) {
|
||||||
|
nn_dropValue(computer->callstack[i]);
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < computer->componentLen; i++) {
|
||||||
|
nn_dropComponent(computer, computer->components[i]);
|
||||||
|
}
|
||||||
|
|
||||||
nn_free(ctx, computer->components, sizeof(nn_Component) * computer->componentCap);
|
nn_free(ctx, computer->components, sizeof(nn_Component) * computer->componentCap);
|
||||||
nn_free(ctx, computer->deviceInfo, sizeof(nn_DeviceInfo) * computer->deviceInfoCap);
|
nn_free(ctx, computer->deviceInfo, sizeof(nn_DeviceInfo) * computer->deviceInfoCap);
|
||||||
nn_strfree(ctx, computer->address);
|
nn_strfree(ctx, computer->address);
|
||||||
@ -779,3 +776,374 @@ nn_Exit nn_tick(nn_Computer *computer) {
|
|||||||
}
|
}
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_addComponent(nn_Computer *computer, nn_ComponentType *ctype, const char *address, int slot, void *userdata) {
|
||||||
|
if(computer->componentLen == computer->componentCap) return NN_ELIMIT;
|
||||||
|
|
||||||
|
nn_Component c;
|
||||||
|
c.address = nn_strdup(&computer->universe->ctx, address);
|
||||||
|
if(c.address == NULL) return NN_ENOMEM;
|
||||||
|
c.ctype = ctype;
|
||||||
|
c.slot = slot;
|
||||||
|
c.userdata = userdata;
|
||||||
|
c.state = NULL;
|
||||||
|
|
||||||
|
nn_ComponentRequest req;
|
||||||
|
req.typeUserdata = ctype->userdata;
|
||||||
|
req.compUserdata = userdata;
|
||||||
|
req.state = NULL;
|
||||||
|
req.computer = computer;
|
||||||
|
req.compAddress = address;
|
||||||
|
req.action = NN_COMP_INIT;
|
||||||
|
req.methodCalled = NULL;
|
||||||
|
|
||||||
|
nn_Exit err = ctype->handler(&req);
|
||||||
|
if(err != NN_OK) {
|
||||||
|
nn_strfree(&computer->universe->ctx, c.address);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
// get the state back!
|
||||||
|
c.state = req.state;
|
||||||
|
|
||||||
|
computer->components[computer->componentLen++] = c;
|
||||||
|
|
||||||
|
// TODO: send the signal
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nn_hasComponent(nn_Computer *computer, const char *address) {
|
||||||
|
for(size_t i = 0; i < computer->componentLen; i++) {
|
||||||
|
nn_Component *c = &computer->components[i];
|
||||||
|
if(nn_strcmp(c->address, address) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nn_hasMethod(nn_Computer *computer, const char *address, const char *method) {
|
||||||
|
for(size_t i = 0; i < computer->componentLen; i++) {
|
||||||
|
nn_Component *c = &computer->components[i];
|
||||||
|
if(nn_strcmp(c->address, address) != 0) continue;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for(size_t j = 0; j < c->ctype->methodCount; j++) {
|
||||||
|
if(nn_strcmp(c->ctype->methods[j].name, method) != 0) continue;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!found) return false;
|
||||||
|
|
||||||
|
nn_ComponentRequest req;
|
||||||
|
req.typeUserdata = c->ctype->userdata;
|
||||||
|
req.compUserdata = c->userdata;
|
||||||
|
req.state = c->state;
|
||||||
|
req.computer = computer;
|
||||||
|
req.compAddress = address;
|
||||||
|
req.action = NN_COMP_ENABLED;
|
||||||
|
req.methodCalled = method;
|
||||||
|
// default response in case it is not implemented
|
||||||
|
req.methodEnabled = true;
|
||||||
|
// should never error
|
||||||
|
c->ctype->handler(&req);
|
||||||
|
|
||||||
|
return req.methodEnabled;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_dropComponent(nn_Computer *computer, nn_Component c) {
|
||||||
|
nn_ComponentRequest req;
|
||||||
|
req.typeUserdata = c.ctype->userdata;
|
||||||
|
req.compUserdata = c.userdata;
|
||||||
|
req.state = c.state;
|
||||||
|
req.computer = computer;
|
||||||
|
req.compAddress = c.address;
|
||||||
|
req.action = NN_COMP_DEINIT;
|
||||||
|
req.methodCalled = NULL;
|
||||||
|
|
||||||
|
c.ctype->handler(&req);
|
||||||
|
|
||||||
|
nn_strfree(&computer->universe->ctx, c.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_removeComponent(nn_Computer *computer, const char *address) {
|
||||||
|
size_t j = 0;
|
||||||
|
nn_Component c;
|
||||||
|
c.address = NULL;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < computer->componentLen; i++) {
|
||||||
|
if(nn_strcmp(computer->components[i].address, address) == 0) {
|
||||||
|
c = computer->components[i];
|
||||||
|
} else {
|
||||||
|
computer->components[j++] = computer->components[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
computer->componentLen = j;
|
||||||
|
|
||||||
|
// already removed!
|
||||||
|
if(c.address == NULL) return NN_EBADSTATE;
|
||||||
|
nn_dropComponent(computer, c);
|
||||||
|
|
||||||
|
// TODO: send the signal
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *nn_getComponentType(nn_Computer *computer, const char *address) {
|
||||||
|
for(size_t i = 0; i < computer->componentLen; i++) {
|
||||||
|
nn_Component *c = &computer->components[i];
|
||||||
|
if(nn_strcmp(c->address, address) == 0) {
|
||||||
|
return c->ctype->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nn_getComponentSlot(nn_Computer *computer, const char *address) {
|
||||||
|
for(size_t i = 0; i < computer->componentLen; i++) {
|
||||||
|
nn_Component *c = &computer->components[i];
|
||||||
|
if(nn_strcmp(c->address, address) == 0) {
|
||||||
|
return c->slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nn_ComponentMethod *nn_getComponentMethods(nn_Computer *computer, const char *address, size_t *len) {
|
||||||
|
for(size_t i = 0; i < computer->componentLen; i++) {
|
||||||
|
nn_Component *c = &computer->components[i];
|
||||||
|
if(nn_strcmp(c->address, address) == 0) {
|
||||||
|
if(len != NULL) *len = c->ctype->methodCount;
|
||||||
|
return c->ctype->methods;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(len != NULL) *len = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_retainValue(nn_Value val) {
|
||||||
|
switch(val.type) {
|
||||||
|
case NN_VAL_NULL:
|
||||||
|
case NN_VAL_BOOL:
|
||||||
|
case NN_VAL_NUM:
|
||||||
|
case NN_VAL_USERDATA:
|
||||||
|
return;
|
||||||
|
case NN_VAL_STR:
|
||||||
|
val.string->refc++;
|
||||||
|
return;
|
||||||
|
case NN_VAL_TABLE:
|
||||||
|
val.table->refc++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nn_dropValue(nn_Value val) {
|
||||||
|
nn_Context ctx;
|
||||||
|
size_t size;
|
||||||
|
switch(val.type) {
|
||||||
|
case NN_VAL_NULL:
|
||||||
|
case NN_VAL_BOOL:
|
||||||
|
case NN_VAL_NUM:
|
||||||
|
case NN_VAL_USERDATA:
|
||||||
|
return;
|
||||||
|
case NN_VAL_STR:
|
||||||
|
val.string->refc--;
|
||||||
|
if(val.string->refc != 0) return;
|
||||||
|
ctx = val.string->ctx;
|
||||||
|
size = val.string->len + 1;
|
||||||
|
nn_free(&ctx, val.string, sizeof(nn_String) + sizeof(char) * size);
|
||||||
|
return;
|
||||||
|
case NN_VAL_TABLE:
|
||||||
|
val.table->refc--;
|
||||||
|
if(val.table->refc != 0) return;
|
||||||
|
ctx = val.table->ctx;
|
||||||
|
size = val.table->len;
|
||||||
|
nn_free(&ctx, val.table, sizeof(nn_Table) + sizeof(nn_Value) * size * 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_call(nn_Computer *computer, const char *address, const char *method);
|
||||||
|
|
||||||
|
bool nn_checkstack(nn_Computer *computer, size_t amount) {
|
||||||
|
return computer->stackSize + amount <= NN_MAX_STACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static nn_Exit nn_pushvalue(nn_Computer *computer, nn_Value val) {
|
||||||
|
if(!nn_checkstack(computer, 1)) {
|
||||||
|
nn_dropValue(val);
|
||||||
|
return NN_ENOSTACK;
|
||||||
|
}
|
||||||
|
computer->callstack[computer->stackSize++] = val;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_pushnull(nn_Computer *computer) {
|
||||||
|
return nn_pushvalue(computer, (nn_Value) {.type = NN_VAL_NULL});
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_pushbool(nn_Computer *computer, bool truthy) {
|
||||||
|
return nn_pushvalue(computer, (nn_Value) {.type = NN_VAL_BOOL, .boolean = truthy});
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_pushnumber(nn_Computer *computer, double num) {
|
||||||
|
return nn_pushvalue(computer, (nn_Value) {.type = NN_VAL_NUM, .number = num});
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_pushstring(nn_Computer *computer, const char *str) {
|
||||||
|
return nn_pushlstring(computer, str, nn_strlen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_pushlstring(nn_Computer *computer, const char *str, size_t len) {
|
||||||
|
nn_Context ctx = computer->universe->ctx;
|
||||||
|
nn_String *s = nn_alloc(&ctx, sizeof(nn_String) + sizeof(char) * (len + 1));
|
||||||
|
if(s == NULL) return NN_ENOMEM;
|
||||||
|
s->ctx = ctx;
|
||||||
|
s->refc = 1;
|
||||||
|
s->len = len;
|
||||||
|
nn_memcpy(s->data, str, sizeof(char) * len);
|
||||||
|
s->data[len] = '\0';
|
||||||
|
return nn_pushvalue(computer, (nn_Value) {.type = NN_VAL_STR, .string = s});
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_pushuserdata(nn_Computer *computer, size_t userdataIdx) {
|
||||||
|
return nn_pushvalue(computer, (nn_Value) {.type = NN_VAL_USERDATA, .userdataIdx = userdataIdx});
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_pusharraytable(nn_Computer *computer, size_t len) {
|
||||||
|
if(computer->stackSize < len) return NN_EBELOWSTACK;
|
||||||
|
nn_Context ctx = computer->universe->ctx;
|
||||||
|
nn_Table *t = nn_alloc(&ctx, sizeof(nn_Table) + sizeof(nn_Value) * len * 2);
|
||||||
|
if(t == NULL) return NN_ENOMEM;
|
||||||
|
t->ctx = ctx;
|
||||||
|
t->refc = 1;
|
||||||
|
t->len = len;
|
||||||
|
for(size_t i = 0; i < len; i++) {
|
||||||
|
t->vals[i*2].type = NN_VAL_NUM;
|
||||||
|
t->vals[i*2].number = (double)i;
|
||||||
|
t->vals[i*2+1] = computer->callstack[computer->stackSize - len + i];
|
||||||
|
}
|
||||||
|
computer->stackSize -= len;
|
||||||
|
return nn_pushvalue(computer, (nn_Value) {.type = NN_VAL_TABLE, .table = t});
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_pushtable(nn_Computer *computer, size_t len) {
|
||||||
|
size_t size = len * 2;
|
||||||
|
if(computer->stackSize < size) return NN_EBELOWSTACK;
|
||||||
|
nn_Context ctx = computer->universe->ctx;
|
||||||
|
nn_Table *t = nn_alloc(&ctx, sizeof(nn_Table) + sizeof(nn_Value) * size);
|
||||||
|
if(t == NULL) return NN_ENOMEM;
|
||||||
|
t->ctx = ctx;
|
||||||
|
t->refc = 1;
|
||||||
|
t->len = len;
|
||||||
|
for(size_t i = 0; i < len*2; i++) {
|
||||||
|
t->vals[i] = computer->callstack[computer->stackSize - size + i];
|
||||||
|
}
|
||||||
|
computer->stackSize -= size;
|
||||||
|
return nn_pushvalue(computer, (nn_Value) {.type = NN_VAL_TABLE, .table = t});
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_pop(nn_Computer *computer) {
|
||||||
|
return nn_popn(computer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_popn(nn_Computer *computer, size_t n) {
|
||||||
|
if(computer->stackSize < n) return NN_EBELOWSTACK;
|
||||||
|
for(size_t i = computer->stackSize - n; i < computer->stackSize; i++) {
|
||||||
|
nn_dropValue(computer->callstack[i]);
|
||||||
|
}
|
||||||
|
computer->stackSize -= n;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_dupe(nn_Computer *computer) {
|
||||||
|
return nn_dupen(computer, 1);
|
||||||
|
}
|
||||||
|
nn_Exit nn_dupen(nn_Computer *computer, size_t n) {
|
||||||
|
if(computer->stackSize < n) return NN_EBELOWSTACK;
|
||||||
|
if(!nn_checkstack(computer, n)) return NN_ENOSTACK;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < n; i++) {
|
||||||
|
nn_Value v = computer->callstack[computer->stackSize - n + i];
|
||||||
|
nn_retainValue(v);
|
||||||
|
computer->callstack[computer->stackSize + i] = v;
|
||||||
|
}
|
||||||
|
computer->stackSize += n;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nn_getstacksize(nn_Computer *computer) {
|
||||||
|
return computer->stackSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nn_clearstack(nn_Computer *computer) {
|
||||||
|
nn_popn(computer, nn_getstacksize(computer));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nn_isnull(nn_Computer *computer, size_t idx) {
|
||||||
|
if(idx < computer->stackSize) return false;
|
||||||
|
return computer->callstack[idx].type == NN_VAL_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nn_isboolean(nn_Computer *computer, size_t idx) {
|
||||||
|
if(idx < computer->stackSize) return false;
|
||||||
|
return computer->callstack[idx].type == NN_VAL_BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nn_isnumber(nn_Computer *computer, size_t idx) {
|
||||||
|
if(idx < computer->stackSize) return false;
|
||||||
|
return computer->callstack[idx].type == NN_VAL_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nn_isstring(nn_Computer *computer, size_t idx) {
|
||||||
|
if(idx < computer->stackSize) return false;
|
||||||
|
return computer->callstack[idx].type == NN_VAL_STR;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nn_isuserdata(nn_Computer *computer, size_t idx) {
|
||||||
|
if(idx < computer->stackSize) return false;
|
||||||
|
return computer->callstack[idx].type == NN_VAL_USERDATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nn_istable(nn_Computer *computer, size_t idx) {
|
||||||
|
if(idx < computer->stackSize) return false;
|
||||||
|
return computer->callstack[idx].type == NN_VAL_TABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nn_toboolean(nn_Computer *computer, size_t idx) {
|
||||||
|
return computer->callstack[idx].boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
double nn_tonumber(nn_Computer *computer, size_t idx) {
|
||||||
|
return computer->callstack[idx].number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *nn_tostring(nn_Computer *computer, size_t idx) {
|
||||||
|
return nn_tolstring(computer, idx, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *nn_tolstring(nn_Computer *computer, size_t idx, size_t *len) {
|
||||||
|
nn_String *s = computer->callstack[idx].string;
|
||||||
|
if(len != NULL) *len = s->len;
|
||||||
|
return s->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t nn_touserdata(nn_Computer *computer, size_t idx) {
|
||||||
|
return computer->callstack[idx].userdataIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
nn_Exit nn_dumptable(nn_Computer *computer, size_t idx, size_t *len) {
|
||||||
|
nn_Table *t = computer->callstack[idx].table;
|
||||||
|
if(!nn_checkstack(computer, t->len * 2)) return NN_ENOSTACK;
|
||||||
|
|
||||||
|
if(len != NULL) *len = t->len;
|
||||||
|
for(size_t i = 0; i < t->len * 2; i++) {
|
||||||
|
computer->callstack[computer->stackSize + i] = t->vals[i];
|
||||||
|
}
|
||||||
|
computer->stackSize += t->len * 2;
|
||||||
|
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: everything
|
||||||
|
nn_Exit nn_initComponentsLibrary(nn_Universe *universe);
|
||||||
|
|||||||
@ -341,12 +341,14 @@ typedef nn_Exit nn_ComponentHandler(nn_ComponentRequest *req);
|
|||||||
|
|
||||||
// Creates a new component type. It is safe to free name and methods afterwards.
|
// Creates a new component type. It is safe to free name and methods afterwards.
|
||||||
nn_ComponentType *nn_createComponentType(nn_Universe *universe, const char *name, void *userdata, const nn_ComponentMethod methods[], nn_ComponentHandler *handler);
|
nn_ComponentType *nn_createComponentType(nn_Universe *universe, const char *name, void *userdata, const nn_ComponentMethod methods[], nn_ComponentHandler *handler);
|
||||||
|
// NOTE: do not destroy this before destroying any components using it, or any computers with components using it.
|
||||||
|
// The component type is still used one last time for the destructor of the components.
|
||||||
void nn_destroyComponentType(nn_ComponentType *ctype);
|
void nn_destroyComponentType(nn_ComponentType *ctype);
|
||||||
|
|
||||||
// adds a component. Outside of the initialization state (aka after the first tick), it also emits the signal for component added.
|
// adds a component. Outside of the initialization state (aka after the first tick), it also emits the signal for component added.
|
||||||
// You MUST NOT destroy the component type while a component using that type still exists.
|
// You MUST NOT destroy the component type while a component using that type still exists.
|
||||||
// You can free the address after the call just fine.
|
// You can free the address after the call just fine.
|
||||||
nn_Exit nn_addComponent(nn_Computer *computer, nn_ComponentType *ctype, const char *address, size_t slot, void *userdata);
|
nn_Exit nn_addComponent(nn_Computer *computer, nn_ComponentType *ctype, const char *address, int slot, void *userdata);
|
||||||
// Checks if a component of that address exists.
|
// Checks if a component of that address exists.
|
||||||
bool nn_hasComponent(nn_Computer *computer, const char *address);
|
bool nn_hasComponent(nn_Computer *computer, const char *address);
|
||||||
// Checks if the component has that method.
|
// Checks if the component has that method.
|
||||||
@ -358,7 +360,7 @@ nn_Exit nn_removeComponent(nn_Computer *computer, const char *address);
|
|||||||
// Gets the name of a type of a component.
|
// Gets the name of a type of a component.
|
||||||
const char *nn_getComponentType(nn_Computer *computer, const char *address);
|
const char *nn_getComponentType(nn_Computer *computer, const char *address);
|
||||||
// Gets the slot of a component.
|
// Gets the slot of a component.
|
||||||
size_t nn_getComponentSlot(nn_Computer *computer, const char *address);
|
int nn_getComponentSlot(nn_Computer *computer, const char *address);
|
||||||
// Returns the array of component methods. This can be used for doc strings or just listing methods.
|
// Returns the array of component methods. This can be used for doc strings or just listing methods.
|
||||||
const nn_ComponentMethod *nn_getComponentMethods(nn_Computer *computer, const char *address, size_t *len);
|
const nn_ComponentMethod *nn_getComponentMethods(nn_Computer *computer, const char *address, size_t *len);
|
||||||
|
|
||||||
@ -373,6 +375,9 @@ nn_Exit nn_call(nn_Computer *computer, const char *address, const char *method);
|
|||||||
// Internally, reference counting is used to manage the memory automatically. The API is designed such that strong reference cycles
|
// Internally, reference counting is used to manage the memory automatically. The API is designed such that strong reference cycles
|
||||||
// cannot occur.
|
// cannot occur.
|
||||||
|
|
||||||
|
// returns if there is enough space for [amount] values
|
||||||
|
bool nn_checkstack(nn_Computer *computer, size_t amount);
|
||||||
|
|
||||||
// pushes a null on the call stack
|
// pushes a null on the call stack
|
||||||
nn_Exit nn_pushnull(nn_Computer *computer);
|
nn_Exit nn_pushnull(nn_Computer *computer);
|
||||||
// pushes a boolean on the call stack
|
// pushes a boolean on the call stack
|
||||||
@ -432,7 +437,7 @@ bool nn_isuserdata(nn_Computer *computer, size_t idx);
|
|||||||
// [idx] starts at 0.
|
// [idx] starts at 0.
|
||||||
bool nn_istable(nn_Computer *computer, size_t idx);
|
bool nn_istable(nn_Computer *computer, size_t idx);
|
||||||
|
|
||||||
// NOTE: behavior of the nn_to*() functions when the types mismatch is undefined.
|
// NOTE: behavior of the nn_to*() functions and nn_dumptable() when the values have the wrong types or at out of bounds indexes is undefined.
|
||||||
|
|
||||||
// Returns the boolean value at [idx].
|
// Returns the boolean value at [idx].
|
||||||
bool nn_toboolean(nn_Computer *computer, size_t idx);
|
bool nn_toboolean(nn_Computer *computer, size_t idx);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user