Scripting: Add doc structs and exporting documentation from engines

This commit is contained in:
Vicki Pfau 2022-09-25 17:29:50 -07:00
parent 73d19cc02a
commit 8e898b02cc
6 changed files with 215 additions and 30 deletions

View File

@ -62,6 +62,8 @@ struct mScriptEngineContext {
bool (*load)(struct mScriptEngineContext*, const char* filename, struct VFile*);
bool (*run)(struct mScriptEngineContext*);
const char* (*getError)(struct mScriptEngineContext*);
struct Table docroot;
};
struct mScriptKVPair {
@ -100,6 +102,10 @@ void mScriptContextRemoveCallback(struct mScriptContext*, uint32_t cbid);
void mScriptContextSetDocstring(struct mScriptContext*, const char* key, const char* docstring);
const char* mScriptContextGetDocstring(struct mScriptContext*, const char* key);
void mScriptEngineExportDocNamespace(struct mScriptEngineContext*, const char* nspace, struct mScriptKVPair* value);
void mScriptEngineSetDocstring(struct mScriptEngineContext*, const char* key, const char* docstring);
const char* mScriptEngineGetDocstring(struct mScriptEngineContext*, const char* key);
struct VFile;
bool mScriptContextLoadVF(struct mScriptContext*, const char* name, struct VFile* vf);
bool mScriptContextLoadFile(struct mScriptContext*, const char* path);

View File

@ -182,6 +182,23 @@ CXX_GUARD_START
.init = false, \
.details = (const struct mScriptClassInitDetails[]) {
#define mSCRIPT_DECLARE_DOC_STRUCT(SCOPE, STRUCT) \
static const struct mScriptType mSTStruct_doc_ ## STRUCT;
#define mSCRIPT_DEFINE_DOC_STRUCT(SCOPE, STRUCT) \
static struct mScriptTypeClass _mSTStructDetails_doc_ ## STRUCT; \
static const struct mScriptType mSTStruct_doc_ ## STRUCT = { \
.base = mSCRIPT_TYPE_OBJECT, \
.details = { \
.cls = &_mSTStructDetails_doc_ ## STRUCT \
}, \
.size = 0, \
.name = SCOPE "::struct::" #STRUCT, \
}; \
static struct mScriptTypeClass _mSTStructDetails_doc_ ## STRUCT = { \
.init = false, \
.details = (const struct mScriptClassInitDetails[]) {
#define mSCRIPT_DEFINE_DOCSTRING(DOCSTRING) { \
.type = mSCRIPT_CLASS_INIT_DOCSTRING, \
.info = { \
@ -338,10 +355,48 @@ CXX_GUARD_START
#define mSCRIPT_DECLARE_STRUCT_VOID_CD_METHOD_WITH_DEFAULTS(TYPE, NAME, NPARAMS, ...) \
mSCRIPT_DECLARE_STRUCT_VOID_C_METHOD_WITH_DEFAULTS(TYPE, NAME, p0->NAME, NPARAMS, __VA_ARGS__)
#define _mSCRIPT_DECLARE_DOC_STRUCT_METHOD(SCOPE, TYPE, NAME, S, NRET, RETURN, NPARAMS, DEFAULTS, ...) \
static const struct mScriptType _mSTStructBindingType_doc_ ## TYPE ## _ ## NAME = { \
.base = mSCRIPT_TYPE_FUNCTION, \
.name = SCOPE "::struct::" #TYPE "." #NAME, \
.details = { \
.function = { \
.parameters = { \
.count = _mSUCC_ ## NPARAMS, \
.entries = { mSCRIPT_TYPE_MS_DS(TYPE), _mCALL(mSCRIPT_PREFIX_ ## NPARAMS, mSCRIPT_TYPE_MS_, _mEVEN_ ## NPARAMS(__VA_ARGS__)) }, \
.names = { "this", _mCALL(_mCALL_ ## NPARAMS, _mSTRINGIFY, _mODD_ ## NPARAMS(__VA_ARGS__)) }, \
.defaults = DEFAULTS, \
}, \
.returnType = { \
.count = NRET, \
.entries = { RETURN } \
}, \
}, \
} \
};
#define mSCRIPT_DECLARE_DOC_STRUCT_METHOD(SCOPE, TYPE, RETURN, NAME, NPARAMS, ...) \
_mSCRIPT_DECLARE_DOC_STRUCT_METHOD(SCOPE, TYPE, NAME, S, 1, mSCRIPT_TYPE_MS_ ## RETURN, NPARAMS, NULL, __VA_ARGS__)
#define mSCRIPT_DECLARE_DOC_STRUCT_VOID_METHOD(SCOPE, TYPE, NAME, NPARAMS, ...) \
_mSCRIPT_DECLARE_DOC_STRUCT_METHOD(SCOPE, TYPE, NAME, S, 0, 0, NPARAMS, NULL, __VA_ARGS__)
#define mSCRIPT_DECLARE_DOC_STRUCT_METHOD_WITH_DEFAULTS(SCOPE, TYPE, RETURN, NAME, NPARAMS, ...) \
static const struct mScriptValue _mSTStructBindingDefaults_doc_ ## TYPE ## _ ## NAME[mSCRIPT_PARAMS_MAX]; \
_mSCRIPT_DECLARE_DOC_STRUCT_METHOD(SCOPE, TYPE, NAME, S, 1, mSCRIPT_TYPE_MS_ ## RETURN, NPARAMS, _mIDENT(_mSTStructBindingDefaults_doc_ ## TYPE ## _ ## NAME), __VA_ARGS__) \
#define mSCRIPT_DECLARE_DOC_STRUCT_VOID_METHOD_WITH_DEFAULTS(SCOPE, TYPE, NAME, NPARAMS, ...) \
static const struct mScriptValue _mSTStructBindingDefaults_doc_ ## TYPE ## _ ## NAME[mSCRIPT_PARAMS_MAX]; \
_mSCRIPT_DECLARE_DOC_STRUCT_METHOD(SCOPE, TYPE, NAME, S, 0, 0, NPARAMS, _mIDENT(_mSTStructBindingDefaults_doc_ ## TYPE ## _ ## NAME), __VA_ARGS__) \
#define mSCRIPT_DEFINE_STRUCT_BINDING_DEFAULTS(TYPE, NAME) \
static const struct mScriptValue _mSTStructBindingDefaults_ ## TYPE ## _ ## NAME[mSCRIPT_PARAMS_MAX] = { \
mSCRIPT_NO_DEFAULT,
#define mSCRIPT_DEFINE_DOC_STRUCT_BINDING_DEFAULTS(SCOPE, TYPE, NAME) \
static const struct mScriptValue _mSTStructBindingDefaults_doc_ ## TYPE ## _ ## NAME[mSCRIPT_PARAMS_MAX] = { \
mSCRIPT_NO_DEFAULT,
#define mSCRIPT_DEFINE_DEFAULTS_END }
#define _mSCRIPT_DEFINE_STRUCT_BINDING(INIT_TYPE, TYPE, EXPORTED_NAME, NAME) { \
@ -366,6 +421,8 @@ CXX_GUARD_START
#define mSCRIPT_DEFINE_STRUCT_DEFAULT_GET(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(GET, TYPE, _get, _get)
#define mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TYPE) _mSCRIPT_DEFINE_STRUCT_BINDING(SET, TYPE, _set, _set)
#define mSCRIPT_DEFINE_DOC_STRUCT_METHOD(SCOPE, TYPE, NAME) mSCRIPT_DEFINE_STRUCT_METHOD_NAMED(doc_ ## TYPE, NAME, NAME)
#define mSCRIPT_DEFINE_STRUCT_CAST_TO_MEMBER(TYPE, CAST_TYPE, MEMBER) { \
.type = mSCRIPT_CLASS_INIT_CAST_TO_MEMBER, \
.info = { \
@ -435,6 +492,39 @@ CXX_GUARD_START
} \
_mSCRIPT_BIND_FUNCTION(NAME, 0, 0, NPARAMS, __VA_ARGS__)
#define _mSCRIPT_DEFINE_DOC_FUNCTION(SCOPE, NAME, NRET, RETURN, NPARAMS, ...) \
static const struct mScriptType _mScriptDocType_ ## NAME = { \
.base = mSCRIPT_TYPE_FUNCTION, \
.name = SCOPE "::function::" #NAME, \
.alloc = NULL, \
.details = { \
.function = { \
.parameters = { \
.count = NPARAMS, \
.entries = { _mCALL(_mIF0_ ## NPARAMS, 0) _mCALL(mSCRIPT_PREFIX_ ## NPARAMS, mSCRIPT_TYPE_MS_, _mEVEN_ ## NPARAMS(__VA_ARGS__)) }, \
.names = { _mCALL(_mIF0_ ## NPARAMS, 0) _mCALL(_mCALL_ ## NPARAMS, _mSTRINGIFY, _mODD_ ## NPARAMS(__VA_ARGS__)) }, \
}, \
.returnType = { \
.count = NRET, \
.entries = { RETURN } \
}, \
}, \
} \
}; \
const struct mScriptValue _mScriptDoc_ ## NAME = { \
.type = &_mScriptDocType_ ## NAME, \
.refs = mSCRIPT_VALUE_UNREF, \
.value = { \
.copaque = NULL \
} \
}
#define mSCRIPT_DEFINE_DOC_FUNCTION(SCOPE, NAME, RETURN, NPARAMS, ...) \
_mSCRIPT_DEFINE_DOC_FUNCTION(SCOPE, NAME, 1, mSCRIPT_TYPE_MS_ ## RETURN, NPARAMS, __VA_ARGS__)
#define mSCRIPT_DEFINE_DOC_VOID_FUNCTION(SCOPE, NAME, NPARAMS, ...) \
_mSCRIPT_DEFINE_DOC_FUNCTION(SCOPE, NAME, 0, 0, NPARAMS, __VA_ARGS__)
#define mSCRIPT_MAKE(TYPE, VALUE) (struct mScriptValue) { \
.type = (mSCRIPT_TYPE_MS_ ## TYPE), \
.refs = mSCRIPT_VALUE_UNREF, \

View File

@ -17,6 +17,8 @@ CXX_GUARD_START
#define mSCRIPT_VALUE_UNREF -1
#define mSCRIPT_PARAMS_MAX 8
#define mSCRIPT_VALUE_DOC_FUNCTION(NAME) (&_mScriptDoc_ ## NAME)
#define mSCRIPT_TYPE_C_S8 int8_t
#define mSCRIPT_TYPE_C_U8 uint8_t
#define mSCRIPT_TYPE_C_S16 int16_t
@ -100,6 +102,7 @@ CXX_GUARD_START
#define mSCRIPT_TYPE_MS_WLIST (&mSTListWrapper)
#define mSCRIPT_TYPE_MS_W(TYPE) (&mSTWrapper_ ## TYPE)
#define mSCRIPT_TYPE_MS_CW(TYPE) (&mSTWrapperConst_ ## TYPE)
#define mSCRIPT_TYPE_MS_DS(STRUCT) (&mSTStruct_doc_ ## STRUCT)
#define mSCRIPT_TYPE_CMP_GENERIC(TYPE0, TYPE1) (TYPE0 == TYPE1)
#define mSCRIPT_TYPE_CMP_U8(TYPE) mSCRIPT_TYPE_CMP_GENERIC(mSCRIPT_TYPE_MS_U8, TYPE)

View File

@ -8,6 +8,8 @@
#include <mgba/internal/script/lua.h>
#endif
#define KEY_NAME_MAX 128
struct mScriptFileInfo {
const char* name;
struct VFile* vf;
@ -302,6 +304,29 @@ const char* mScriptContextGetDocstring(struct mScriptContext* context, const cha
return HashTableLookup(&context->docstrings, key);
}
void mScriptEngineExportDocNamespace(struct mScriptEngineContext* ctx, const char* nspace, struct mScriptKVPair* values) {
struct mScriptValue* table = mScriptValueAlloc(mSCRIPT_TYPE_MS_TABLE);
size_t i;
for (i = 0; values[i].key; ++i) {
struct mScriptValue* key = mScriptStringCreateFromUTF8(values[i].key);
mScriptTableInsert(table, key, values[i].value);
mScriptValueDeref(key);
}
HashTableInsert(&ctx->docroot, nspace, table);
}
void mScriptEngineSetDocstring(struct mScriptEngineContext* ctx, const char* key, const char* docstring) {
char scopedKey[KEY_NAME_MAX];
snprintf(scopedKey, sizeof(scopedKey), "%s::%s", ctx->engine->name, key);
HashTableInsert(&ctx->context->docstrings, scopedKey, (char*) docstring);
}
const char* mScriptEngineGetDocstring(struct mScriptEngineContext* ctx, const char* key) {
char scopedKey[KEY_NAME_MAX];
snprintf(scopedKey, sizeof(scopedKey), "%s::%s", ctx->engine->name, key);
return HashTableLookup(&ctx->context->docstrings, scopedKey);
}
bool mScriptContextLoadVF(struct mScriptContext* context, const char* name, struct VFile* vf) {
struct mScriptFileInfo info = {
.name = name,

View File

@ -7,12 +7,33 @@
#include <mgba/core/scripting.h>
#include <mgba/core/version.h>
#include <mgba/script/context.h>
#include <mgba-util/string.h>
struct mScriptContext context;
struct Table types;
FILE* out;
const struct mScriptType* const baseTypes[] = {
mSCRIPT_TYPE_MS_S8,
mSCRIPT_TYPE_MS_U8,
mSCRIPT_TYPE_MS_S16,
mSCRIPT_TYPE_MS_U16,
mSCRIPT_TYPE_MS_S32,
mSCRIPT_TYPE_MS_U32,
mSCRIPT_TYPE_MS_F32,
mSCRIPT_TYPE_MS_S64,
mSCRIPT_TYPE_MS_U64,
mSCRIPT_TYPE_MS_F64,
mSCRIPT_TYPE_MS_STR,
mSCRIPT_TYPE_MS_CHARP,
mSCRIPT_TYPE_MS_LIST,
mSCRIPT_TYPE_MS_TABLE,
mSCRIPT_TYPE_MS_WRAPPER,
NULL
};
void explainValue(struct mScriptValue* value, const char* name, int level);
void explainValueScoped(struct mScriptValue* value, const char* name, const char* scope, int level);
void explainType(struct mScriptType* type, int level);
void addTypesFromTuple(const struct mScriptTypeTuple*);
@ -154,7 +175,7 @@ bool printval(const struct mScriptValue* value, char* buffer, size_t bufferSize)
return false;
}
void explainTable(struct mScriptValue* value, const char* name, int level) {
void explainTable(struct mScriptValue* value, const char* name, const char* scope, int level) {
char indent[(level + 1) * 2 + 1];
memset(indent, ' ', sizeof(indent) - 1);
indent[sizeof(indent) - 1] = '\0';
@ -171,9 +192,9 @@ void explainTable(struct mScriptValue* value, const char* name, int level) {
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);
explainValueScoped(v, keyval, scope, level + 1);
} else {
explainValue(v, NULL, level + 1);
explainValueScoped(v, NULL, scope, level + 1);
}
} while (mScriptTableIteratorNext(value, &iter));
}
@ -250,6 +271,10 @@ void explainObject(struct mScriptValue* value, int level) {
}
void explainValue(struct mScriptValue* value, const char* name, int level) {
explainValueScoped(value, name, NULL, level);
}
void explainValueScoped(struct mScriptValue* value, const char* name, const char* scope, int level) {
char valstring[1024];
char indent[(level + 1) * 2 + 1];
memset(indent, ' ', sizeof(indent) - 1);
@ -260,7 +285,12 @@ void explainValue(struct mScriptValue* value, const char* name, int level) {
const char* docstring = NULL;
if (name) {
docstring = mScriptContextGetDocstring(&context, name);
if (scope) {
snprintf(valstring, sizeof(valstring), "%s::%s", scope, name);
docstring = mScriptContextGetDocstring(&context, valstring);
} else {
docstring = mScriptContextGetDocstring(&context, name);
}
}
if (docstring) {
fprintf(out, "%scomment: \"%s\"\n", indent, docstring);
@ -269,7 +299,7 @@ void explainValue(struct mScriptValue* value, const char* name, int level) {
switch (value->type->base) {
case mSCRIPT_TYPE_TABLE:
fprintf(out, "%svalue:\n", indent);
explainTable(value, name, level);
explainTable(value, name, scope, level);
break;
case mSCRIPT_TYPE_SINT:
case mSCRIPT_TYPE_UINT:
@ -438,6 +468,35 @@ void explainCore(struct mCore* core) {
mScriptContextDetachCore(&context);
}
void initTypes(void) {
HashTableInit(&types, 0, NULL);
size_t i;
for (i = 0; baseTypes[i]; ++i) {
addType(baseTypes[i]);
}
}
void explainTypes(int level, const char* prefix) {
char indent[level * 2 + 1];
memset(indent, ' ', sizeof(indent) - 1);
indent[sizeof(indent) - 1] = '\0';
fprintf(out, "%stypes:\n", indent);
struct TableIterator iter;
if (HashTableIteratorStart(&types, &iter)) {
do {
const char* name = HashTableIteratorGetKey(&types, &iter);
struct mScriptType* type = HashTableIteratorGetValue(&types, &iter);
if (prefix && !startswith(name, prefix)) {
continue;
}
fprintf(out, "%s %s:\n", indent, name);
explainType(type, level + 1);
} while (HashTableIteratorNext(&types, &iter));
}
}
int main(int argc, char* argv[]) {
out = stdout;
if (argc > 1) {
@ -450,24 +509,10 @@ int main(int argc, char* argv[]) {
mScriptContextInit(&context);
mScriptContextAttachStdlib(&context);
mScriptContextAttachSocket(&context);
mScriptContextSetTextBufferFactory(&context, NULL, NULL);
HashTableInit(&types, 0, NULL);
addType(mSCRIPT_TYPE_MS_S8);
addType(mSCRIPT_TYPE_MS_U8);
addType(mSCRIPT_TYPE_MS_S16);
addType(mSCRIPT_TYPE_MS_U16);
addType(mSCRIPT_TYPE_MS_S32);
addType(mSCRIPT_TYPE_MS_U32);
addType(mSCRIPT_TYPE_MS_F32);
addType(mSCRIPT_TYPE_MS_S64);
addType(mSCRIPT_TYPE_MS_U64);
addType(mSCRIPT_TYPE_MS_F64);
addType(mSCRIPT_TYPE_MS_STR);
addType(mSCRIPT_TYPE_MS_CHARP);
addType(mSCRIPT_TYPE_MS_LIST);
addType(mSCRIPT_TYPE_MS_TABLE);
addType(mSCRIPT_TYPE_MS_WRAPPER);
initTypes();
fputs("version:\n", out);
fprintf(out, " string: \"%s\"\n", projectVersion);
@ -498,16 +543,28 @@ int main(int argc, char* argv[]) {
explainCore(core);
core->deinit(core);
}
fputs("types:\n", out);
if (HashTableIteratorStart(&types, &iter)) {
do {
const char* name = HashTableIteratorGetKey(&types, &iter);
fprintf(out, " %s:\n", name);
struct mScriptType* type = HashTableIteratorGetValue(&types, &iter);
explainType(type, 1);
} while (HashTableIteratorNext(&types, &iter));
}
explainTypes(0, NULL);
mScriptContextRegisterEngines(&context);
fputs("engines:\n", out);
if (HashTableIteratorStart(&context.engines, &iter)) {
do {
struct TableIterator rootIter;
struct mScriptEngineContext* engine = HashTableIteratorGetValue(&context.engines, &iter);
const char* name = HashTableIteratorGetKey(&context.engines, &iter);
fprintf(out, " %s:\n root:\n", name);
if (HashTableIteratorStart(&engine->docroot, &rootIter)) {
do {
const char* key = HashTableIteratorGetKey(&engine->docroot, &rootIter);
struct mScriptValue* value = HashTableIteratorGetValue(&engine->docroot, &rootIter);
fprintf(out, " %s:\n", key);
explainValueScoped(value, key, name, 3);
} while (HashTableIteratorNext(&engine->docroot, &rootIter));
}
explainTypes(2, name);
} while (HashTableIteratorNext(&context.engines, &iter));
}
HashTableDeinit(&types);
mScriptContextDeinit(&context);
return 0;

View File

@ -333,6 +333,8 @@ struct mScriptEngineContext* _luaCreate(struct mScriptEngine2* engine, struct mS
lua_getglobal(luaContext->lua, "require");
luaContext->require = luaL_ref(luaContext->lua, LUA_REGISTRYINDEX);
HashTableInit(&luaContext->d.docroot, 0, (void (*)(void*)) mScriptValueDeref);
int status = luaL_dostring(luaContext->lua, _socketLuaSource);
if (status) {
mLOG(SCRIPT, ERROR, "Error in dostring while initializing sockets: %s\n", lua_tostring(luaContext->lua, -1));
@ -369,6 +371,8 @@ void _luaDestroy(struct mScriptEngineContext* ctx) {
luaL_unref(luaContext->lua, LUA_REGISTRYINDEX, luaContext->require);
}
lua_close(luaContext->lua);
HashTableDeinit(&luaContext->d.docroot);
free(luaContext);
}