spiegel-keyman/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp
Marc Durdin 6462b5fc63 refactor(developer): kmc-kmn now builds .js when needed
kmc-kmn calls into kmc-kmw to build .js when it is needed, rather than
kmc-kmw depending on kmc-kmn. This means examining the `&targets` system store
to determine which files need to be generated.

This also implements the `&displayMap` rewrite for both .kvks and
.keyman-touch-layout as part of the KMW compiler.

I suspect that the next step is to place kmc-kmw into a subfolder of
kmc-kmn, given they are part of the same process, and there is no
practical way to separate out the .js generation from the .kmx
generation.
2023-06-19 15:25:09 +07:00

126 lines
4 KiB
C++

#include "pch.h"
#include <kmcmplibapi.h>
#ifdef __EMSCRIPTEN__
/*
WASM interface for compiler message callback
*/
EM_JS(int, wasm_msgproc, (int line, int msgcode, const char* text, char* context), {
const proc = globalThis[UTF8ToString(context)].message;
if(!proc || typeof proc != 'function') {
console.log(`[${line}: ${msgcode}: ${UTF8ToString(text)}]`);
return 0;
} else {
return proc(line, msgcode, UTF8ToString(text));
}
});
EM_JS(int, wasm_loadfileproc, (const char* filename, const char* baseFilename, void* buffer, int bufferSize, char* context), {
const proc = globalThis[UTF8ToString(context)].loadFile;
if(!proc || typeof proc != 'function') {
return 0;
} else {
if(buffer == 0) {
return proc(UTF8ToString(filename), UTF8ToString(baseFilename), 0, 0);
} else {
return proc(UTF8ToString(filename), UTF8ToString(baseFilename), buffer, bufferSize);
}
}
});
bool wasm_LoadFileProc(const char* filename, const char* baseFilename, void* buffer, int* bufferSize, void* context) {
char* msgProc = static_cast<char*>(context);
if(buffer == nullptr) {
*bufferSize = wasm_loadfileproc(filename, baseFilename, 0, 0, msgProc);
return *bufferSize != -1;
} else {
return wasm_loadfileproc(filename, baseFilename, buffer, *bufferSize, msgProc) == 1;
}
}
int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, const char* szText, void* context) {
char* msgProc = static_cast<char*>(context);
return wasm_msgproc(line, dwMsgCode, szText, msgProc);
}
struct WASM_COMPILER_INTERFACE {
std::string callbacksKey; // key of callbacks object on globalThis
};
struct WASM_COMPILER_RESULT {
bool result;
// Following are pointer offsets in heap + buffer size
int kmx;
int kmxSize;
// Following are compiler side-channel data, required for
// follow-on transform
int targets; /* COMPILETARGETS_KMX | COMPILETARGETS_JS */
std::string kvksFilename;
std::string displayMapFilename;
// TODO: additional data to be passed back
};
WASM_COMPILER_RESULT kmcmp_wasm_compile(std::string pszInfile, const KMCMP_COMPILER_OPTIONS options, const WASM_COMPILER_INTERFACE intf) {
WASM_COMPILER_RESULT r;
KMCMP_COMPILER_RESULT kr;
r.result = false;
r.kmx = 0;
r.kmxSize = 0;
r.targets = 0;
r.kvksFilename = "";
r.displayMapFilename = "";
r.result = kmcmp_CompileKeyboard(
pszInfile.c_str(),
options,
wasm_CompilerMessageProc,
wasm_LoadFileProc,
intf.callbacksKey.c_str(),
kr
);
if(r.result) {
// TODO: additional data as required by kmc_kmw
r.kmx = (int) kr.kmx;
r.kmxSize = (int) kr.kmxSize;
r.kvksFilename = kr.kvksFilename;
r.displayMapFilename = kr.displayMapFilename;
r.targets = kr.targets;
}
return r;
}
EMSCRIPTEN_BINDINGS(compiler_interface) {
emscripten::class_<KMCMP_COMPILER_OPTIONS>("CompilerOptions")
.constructor<>()
.property("saveDebug", &KMCMP_COMPILER_OPTIONS::saveDebug)
.property("compilerWarningsAsErrors", &KMCMP_COMPILER_OPTIONS::compilerWarningsAsErrors)
.property("warnDeprecatedCode", &KMCMP_COMPILER_OPTIONS::warnDeprecatedCode)
.property("shouldAddCompilerVersion", &KMCMP_COMPILER_OPTIONS::shouldAddCompilerVersion)
.property("target", &KMCMP_COMPILER_OPTIONS::target)
;
emscripten::class_<WASM_COMPILER_INTERFACE>("CompilerInterface")
.constructor<>()
.property("callbacksKey", &WASM_COMPILER_INTERFACE::callbacksKey)
;
emscripten::class_<WASM_COMPILER_RESULT>("CompilerResult")
.constructor<>()
.property("result", &WASM_COMPILER_RESULT::result)
.property("kmx", &WASM_COMPILER_RESULT::kmx)
.property("kmxSize", &WASM_COMPILER_RESULT::kmxSize)
.property("targets", &WASM_COMPILER_RESULT::targets)
.property("kvksFilename", &WASM_COMPILER_RESULT::kvksFilename)
.property("displayMapFilename", &WASM_COMPILER_RESULT::displayMapFilename)
;
emscripten::function("kmcmp_compile", &kmcmp_wasm_compile);
emscripten::function("kmcmp_parseUnicodeSet", &kmcmp_parseUnicodeSet);
}
#endif