calog/src/mybasic/mybasicEngine.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);
}