// 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 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); }