diff --git a/include/mgba/script/context.h b/include/mgba/script/context.h index 780067d83..80682ee29 100644 --- a/include/mgba/script/context.h +++ b/include/mgba/script/context.h @@ -30,6 +30,7 @@ struct mScriptContext { uint32_t nextWeakref; struct Table callbacks; struct mScriptValue* constants; + struct Table docstrings; }; struct mScriptEngine2 { @@ -86,6 +87,9 @@ void mScriptContextExportNamespace(struct mScriptContext* context, const char* n void mScriptContextTriggerCallback(struct mScriptContext*, const char* callback); void mScriptContextAddCallback(struct mScriptContext*, const char* callback, struct mScriptValue* value); +void mScriptContextSetDocstring(struct mScriptContext*, const char* key, const char* docstring); +const char* mScriptContextGetDocstring(struct mScriptContext*, const char* key); + struct VFile; bool mScriptContextLoadVF(struct mScriptContext*, const char* name, struct VFile* vf); bool mScriptContextLoadFile(struct mScriptContext*, const char* path); diff --git a/src/core/scripting.c b/src/core/scripting.c index d08761bbf..7c14eb08b 100644 --- a/src/core/scripting.c +++ b/src/core/scripting.c @@ -710,14 +710,20 @@ mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(mScriptConsole, createBuffer) mSCRIPT_CHARP(NULL) mSCRIPT_DEFINE_DEFAULTS_END; -void mScriptContextAttachLogger(struct mScriptContext* context, struct mLogger* logger) { +static struct mScriptConsole* _ensureConsole(struct mScriptContext* context) { struct mScriptValue* value = mScriptContextEnsureGlobal(context, "console", mSCRIPT_TYPE_MS_S(mScriptConsole)); struct mScriptConsole* console = value->value.opaque; if (!console) { console = calloc(1, sizeof(*console)); value->value.opaque = console; value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER; + mScriptContextSetDocstring(context, "console", "Singleton instance of struct::mScriptConsole"); } + return console; +} + +void mScriptContextAttachLogger(struct mScriptContext* context, struct mLogger* logger) { + struct mScriptConsole* console = _ensureConsole(context); console->logger = logger; } @@ -771,14 +777,7 @@ mSCRIPT_DEFINE_STRUCT(mScriptTextBuffer) mSCRIPT_DEFINE_END; void mScriptContextSetTextBufferFactory(struct mScriptContext* context, mScriptContextBufferFactory factory, void* cbContext) { - struct mScriptValue* value = mScriptContextEnsureGlobal(context, "console", mSCRIPT_TYPE_MS_S(mScriptConsole)); - struct mScriptConsole* console = value->value.opaque; - if (!console) { - console = calloc(1, sizeof(*console)); - console->logger = mLogGetContext(); - value->value.opaque = console; - value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER; - } + struct mScriptConsole* console = _ensureConsole(context); console->textBufferFactory = factory; console->textBufferContext = cbContext; } diff --git a/src/script/context.c b/src/script/context.c index 43f962caf..7c9b32dab 100644 --- a/src/script/context.c +++ b/src/script/context.c @@ -57,6 +57,7 @@ void mScriptContextInit(struct mScriptContext* context) { context->nextWeakref = 1; HashTableInit(&context->callbacks, 0, (void (*)(void*)) mScriptValueDeref); context->constants = NULL; + HashTableInit(&context->docstrings, 0, NULL); } void mScriptContextDeinit(struct mScriptContext* context) { @@ -66,6 +67,7 @@ void mScriptContextDeinit(struct mScriptContext* context) { mScriptListDeinit(&context->refPool); HashTableDeinit(&context->callbacks); HashTableDeinit(&context->engines); + HashTableDeinit(&context->docstrings); } void mScriptContextFillPool(struct mScriptContext* context, struct mScriptValue* value) { @@ -249,6 +251,14 @@ void mScriptContextExportNamespace(struct mScriptContext* context, const char* n mScriptContextSetGlobal(context, nspace, table); } +void mScriptContextSetDocstring(struct mScriptContext* context, const char* key, const char* docstring) { + HashTableInsert(&context->docstrings, key, docstring); +} + +const char* mScriptContextGetDocstring(struct mScriptContext* context, const char* key) { + return HashTableLookup(&context->docstrings, key); +} + bool mScriptContextLoadVF(struct mScriptContext* context, const char* name, struct VFile* vf) { struct mScriptFileInfo info = { .name = name, diff --git a/src/script/docgen.c b/src/script/docgen.c index bc16bc9b7..519b73bb2 100644 --- a/src/script/docgen.c +++ b/src/script/docgen.c @@ -12,7 +12,7 @@ struct mScriptContext context; struct Table types; FILE* out; -void explainValue(struct mScriptValue* value, int level); +void explainValue(struct mScriptValue* value, const char* name, int level); void explainType(struct mScriptType* type, int level); void addTypesFromTuple(const struct mScriptTypeTuple*); @@ -154,7 +154,7 @@ bool printval(const struct mScriptValue* value, char* buffer, size_t bufferSize) return false; } -void explainTable(struct mScriptValue* value, int level) { +void explainTable(struct mScriptValue* value, const char* name, int level) { char indent[(level + 1) * 2 + 1]; memset(indent, ' ', sizeof(indent) - 1); indent[sizeof(indent) - 1] = '\0'; @@ -167,7 +167,14 @@ void explainTable(struct mScriptValue* value, int level) { printval(k, keyval, sizeof(keyval)); fprintf(out, "%s- key: %s\n", indent, keyval); struct mScriptValue* v = mScriptTableIteratorGetValue(value, &iter); - explainValue(v, level + 1); + + struct mScriptValue string; + if (mScriptCast(mSCRIPT_TYPE_MS_CHARP, k, &string)) { + snprintf(keyval, sizeof(keyval), "%s.%s", name, (const char*) string.value.opaque); + explainValue(v, keyval, level + 1); + } else { + explainValue(v, NULL, level + 1); + } } while (mScriptTableIteratorNext(value, &iter)); } } @@ -234,15 +241,15 @@ void explainObject(struct mScriptValue* value, int level) { struct mScriptValue* unwrappedMember; if (member.type->base == mSCRIPT_TYPE_WRAPPER) { unwrappedMember = mScriptValueUnwrap(&member); - explainValue(unwrappedMember, level + 2); + explainValue(unwrappedMember, NULL, level + 2); } else { - explainValue(&member, level + 2); + explainValue(&member, NULL, level + 2); } } } } -void explainValue(struct mScriptValue* value, int level) { +void explainValue(struct mScriptValue* value, const char* name, int level) { char valstring[1024]; char indent[(level + 1) * 2 + 1]; memset(indent, ' ', sizeof(indent) - 1); @@ -250,10 +257,19 @@ void explainValue(struct mScriptValue* value, int level) { value = mScriptContextAccessWeakref(&context, value); addType(value->type); fprintf(out, "%stype: %s\n", indent, value->type->name); + + const char* docstring = NULL; + if (name) { + docstring = mScriptContextGetDocstring(&context, name); + } + if (docstring) { + fprintf(out, "%scomment: \"%s\"\n", indent, docstring); + } + switch (value->type->base) { case mSCRIPT_TYPE_TABLE: fprintf(out, "%svalue:\n", indent); - explainTable(value, level); + explainTable(value, name, level); break; case mSCRIPT_TYPE_SINT: case mSCRIPT_TYPE_UINT: @@ -462,7 +478,7 @@ int main(int argc, char* argv[]) { const char* name = HashTableIteratorGetKey(&context.rootScope, &iter); fprintf(out, " %s:\n", name); struct mScriptValue* value = HashTableIteratorGetValue(&context.rootScope, &iter); - explainValue(value, 1); + explainValue(value, name, 1); } while (HashTableIteratorNext(&context.rootScope, &iter)); } fputs("emu:\n", out); diff --git a/src/script/stdlib.c b/src/script/stdlib.c index 32770a752..695946d05 100644 --- a/src/script/stdlib.c +++ b/src/script/stdlib.c @@ -90,6 +90,7 @@ void mScriptContextAttachStdlib(struct mScriptContext* context) { }; lib->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER; mScriptContextSetGlobal(context, "callbacks", lib); + mScriptContextSetDocstring(context, "callbacks", "Singleton instance of struct::mScriptCallbackManager"); mScriptContextExportConstants(context, "SAVESTATE", (struct mScriptKVPair[]) { mSCRIPT_CONSTANT_PAIR(SAVESTATE, SCREENSHOT), @@ -139,10 +140,14 @@ void mScriptContextAttachStdlib(struct mScriptContext* context) { }); #endif mScriptContextSetGlobal(context, "C", context->constants); + mScriptContextSetDocstring(context, "C", "A table containing the [exported constants](#constants)"); mScriptContextExportNamespace(context, "util", (struct mScriptKVPair[]) { mSCRIPT_KV_PAIR(makeBitmask, &mScriptMakeBitmask_Binding), mSCRIPT_KV_PAIR(expandBitmask, &mScriptExpandBitmask_Binding), mSCRIPT_KV_SENTINEL }); + mScriptContextSetDocstring(context, "util", "Basic utility library"); + mScriptContextSetDocstring(context, "util.makeBitmask", "Compile a list of bit indices into a bitmask"); + mScriptContextSetDocstring(context, "util.expandBitmask", "Expand a bitmask into a list of bit indices"); }