75 lines
2.6 KiB
C
75 lines
2.6 KiB
C
// mybasicEngine.c -- bridges the my-basic adapter to the actor layer's CalogEngineT
|
|
// vtable, so a my-basic interpreter runs on its own context thread and is loadable by
|
|
// file extension (.bas) via calogContextLoad.
|
|
//
|
|
// The engine is vendor/ourbasic -- calog's fork of MY-BASIC (see vendor/ourbasic/NOTICE +
|
|
// CHANGELOG; pristine upstream kept as ourBasic.c.upstream). my-basic keeps a little
|
|
// process-global state, but only two things are shared across interpreters: an allocation
|
|
// counter (patched to _Atomic in vendor/ourbasic/ourBasic.c) and the mb_init singletons,
|
|
// which are built once and are read-only thereafter. So interpreters EXECUTE in parallel;
|
|
// only lifecycle needs
|
|
// serializing -- mb_init's lazy build on the first context, mb_dispose on the last, and
|
|
// the adapter's shared context refcount. This lock covers just create and destroy;
|
|
// runSource runs unlocked, so several my-basic scripts run at once.
|
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
#include "calogInternal.h"
|
|
#include "mybasicAdapter.h"
|
|
|
|
#include <pthread.h>
|
|
|
|
static int32_t mybasicEngineCreate(CalogContextT *context, void **interpOut);
|
|
static void mybasicEngineDestroy(void *interp);
|
|
static int32_t mybasicEngineRun(void *interp, const char *source, CalogValueT *result);
|
|
static void mybasicExposeVisitor(const CalogEntryT *entry, void *ud);
|
|
|
|
static const char *const mybasicExtensions[] = { "bas", NULL };
|
|
|
|
const CalogEngineT calogMyBasicEngine = {
|
|
"mybasic",
|
|
mybasicExtensions,
|
|
mybasicEngineCreate,
|
|
mybasicEngineDestroy,
|
|
mybasicEngineRun
|
|
};
|
|
|
|
|
|
static int32_t mybasicEngineCreate(CalogContextT *context, void **interpOut) {
|
|
CalogMyBasicT *mb;
|
|
int32_t status;
|
|
|
|
*interpOut = NULL;
|
|
calogMyBasicLifecycleLock();
|
|
status = calogMyBasicCreate(&mb, calogContextBroker(context), calogContextId(context));
|
|
if (status == calogOkE) {
|
|
calogForEach(calogContextBroker(context), mybasicExposeVisitor, mb);
|
|
*interpOut = mb;
|
|
}
|
|
calogMyBasicLifecycleUnlock();
|
|
return status;
|
|
}
|
|
|
|
|
|
static void mybasicEngineDestroy(void *interp) {
|
|
calogMyBasicLifecycleLock();
|
|
calogMyBasicDestroy((CalogMyBasicT *)interp);
|
|
calogMyBasicLifecycleUnlock();
|
|
}
|
|
|
|
|
|
static int32_t mybasicEngineRun(void *interp, const char *source, CalogValueT *result) {
|
|
int32_t status;
|
|
|
|
calogValueNil(result);
|
|
status = calogMyBasicRun((CalogMyBasicT *)interp, source);
|
|
if (status != calogOkE) {
|
|
return calogFail(result, status, "my-basic script failed");
|
|
}
|
|
return calogOkE;
|
|
}
|
|
|
|
|
|
static void mybasicExposeVisitor(const CalogEntryT *entry, void *ud) {
|
|
calogMyBasicExpose((CalogMyBasicT *)ud, entry->name);
|
|
}
|