From c3ecae4e98ce2898949bb0d60e68b3802b4e37b0 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Thu, 1 Jun 2023 05:29:19 +0700 Subject: [PATCH] refactor(developer): rearrange kmcmplib interface source Fixes #8889. No code changes, just moves WASM interfaces into CompilerInterfacesWasm.cpp, and CompileKeyboardHandle is renamed to CompileKeyboardBuffer and moved into its own source file. --- .../kmcmplib/src/CompileKeyboardBuffer.cpp | 166 ++++++++++ .../src/kmcmplib/src/CompileKeyboardBuffer.h | 5 + .../src/kmcmplib/src/CompilerInterfaces.cpp | 285 +----------------- .../kmcmplib/src/CompilerInterfacesWasm.cpp | 117 +++++++ developer/src/kmcmplib/src/meson.build | 2 + 5 files changed, 292 insertions(+), 283 deletions(-) create mode 100644 developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp create mode 100644 developer/src/kmcmplib/src/CompileKeyboardBuffer.h create mode 100644 developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp diff --git a/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp b/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp new file mode 100644 index 0000000000..c932f68a4f --- /dev/null +++ b/developer/src/kmcmplib/src/CompileKeyboardBuffer.cpp @@ -0,0 +1,166 @@ +#include "pch.h" +#include +#include "kmcmplib.h" +#include "CheckFilenameConsistency.h" +#include "CheckNCapsConsistency.h" +#include "DeprecationChecks.h" +#include "versioning.h" +#include "CompileKeyboardBuffer.h" +#include "../../../../common/windows/cpp/include/keymanversion.h" + +bool CompileKeyboardBuffer(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) +{ + PKMX_WCHAR str, p; + + KMX_DWORD msg; + + kmcmp::FMnemonicLayout = FALSE; + + if (!fk) { + AddCompileError(CERR_SomewhereIGotItWrong); + return FALSE; + } + + str = new KMX_WCHAR[LINESIZE]; + if (!str) { + AddCompileError(CERR_CannotAllocateMemory); + return FALSE; + } + + fk->KeyboardID = 0; + fk->version = 0; + fk->dpStoreArray = NULL; + fk->dpGroupArray = NULL; + fk->cxStoreArray = 0; + fk->cxGroupArray = 0; + fk->StartGroup[0] = fk->StartGroup[1] = -1; + fk->szName[0] = 0; + fk->szCopyright[0] = 0; + fk->dwFlags = KF_AUTOMATICVERSION; + fk->currentGroup = 0xFFFFFFFF; + fk->currentStore = 0; + fk->cxDeadKeyArray = 0; + fk->dpDeadKeyArray = NULL; + fk->cxVKDictionary = 0; // I3438 + fk->dpVKDictionary = NULL; // I3438 + fk->extra->kvksFilename = u""; +/* fk->szMessage[0] = 0; + fk->szLanguageName[0] = 0;*/ + fk->dwBitmapSize = 0; + fk->dwHotKey = 0; + + kmcmp::BeginLine[BEGIN_ANSI] = -1; + kmcmp::BeginLine[BEGIN_UNICODE] = -1; + kmcmp::BeginLine[BEGIN_NEWCONTEXT] = -1; + kmcmp::BeginLine[BEGIN_POSTKEYSTROKE] = -1; + + + /* Add a store for the Keyman 6.0 copyright information string */ + + if(kmcmp::FShouldAddCompilerVersion) { + u16sprintf(str,LINESIZE, L"Created with Keyman Developer version %d.%d.%d.%d", KEYMAN_VersionMajor, KEYMAN_VersionMinor, KEYMAN_VersionPatch, 0); + AddStore(fk, TSS_KEYMANCOPYRIGHT, str); + } + + /* Add a system store for the Keyman edition number */ + AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0"); + AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman"); + + int offset = 0; + + // must preprocess for group and store names -> this isn't really necessary, but never mind! + while ((msg = ReadLine(infile, sz, offset, str, TRUE)) == CERR_None) + { + p = str; + switch (LineTokenType(&p)) + { + case T_VERSION: + *(p + 4) = 0; + if ((msg = AddStore(fk, TSS_VERSION, p)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + break; + + case T_GROUP: + if ((msg = ProcessGroupLine(fk, p)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + break; + + case T_STORE: + if ((msg = ProcessStoreLine(fk, p)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + break; + + default: + break; + } + } + + if (msg != CERR_EndOfFile) { + AddCompileError(msg); + return FALSE; + } + + offset = 0; + kmcmp::currentLine = 0; + + /* Reindex the list of codeconstants after stores added */ + + kmcmp::CodeConstants->reindex(); + + /* ReadLine will automatically skip over $Keyman lines, and parse wrapped lines */ + while ((msg = ReadLine(infile, sz, offset, str, FALSE)) == CERR_None) + { + msg = ParseLine(fk, str); + if (msg != CERR_None) { + AddCompileError(msg); + return FALSE; + } + } + + if (msg != CERR_EndOfFile) { + AddCompileError(msg); + return FALSE; + } + + ProcessGroupFinish(fk); + + if (kmcmp::FSaveDebug) kmcmp::RecordDeadkeyNames(fk); + + /* Add the compiler version as a system store */ + if ((msg = kmcmp::AddCompilerVersionStore(fk)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + + if ((msg = BuildVKDictionary(fk)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + + if ((msg = CheckFilenameConsistencyForCalls(fk)) != CERR_None) { + AddCompileError(msg); + return FALSE; + } + + delete str; + + if (!kmcmp::CheckKeyboardFinalVersion(fk)) { + return FALSE; + } + + /* Warn on inconsistent use of NCAPS */ + if (!kmcmp::FMnemonicLayout) { + CheckNCapsConsistency(fk); + } + + /* Flag presence of deprecated features */ + kmcmp::CheckForDeprecatedFeatures(fk); + + return TRUE; +} diff --git a/developer/src/kmcmplib/src/CompileKeyboardBuffer.h b/developer/src/kmcmplib/src/CompileKeyboardBuffer.h new file mode 100644 index 0000000000..78bac66653 --- /dev/null +++ b/developer/src/kmcmplib/src/CompileKeyboardBuffer.h @@ -0,0 +1,5 @@ +#pragma once + +#include "compfile.h" + +bool CompileKeyboardBuffer(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); diff --git a/developer/src/kmcmplib/src/CompilerInterfaces.cpp b/developer/src/kmcmplib/src/CompilerInterfaces.cpp index 16b5b98654..fdfbdf1961 100644 --- a/developer/src/kmcmplib/src/CompilerInterfaces.cpp +++ b/developer/src/kmcmplib/src/CompilerInterfaces.cpp @@ -1,134 +1,9 @@ #include "pch.h" - #include #include #include "kmcmplib.h" -#include "CheckFilenameConsistency.h" -#include "CheckNCapsConsistency.h" -#include "DeprecationChecks.h" -#include "versioning.h" #include "../../../../common/windows/cpp/include/ConvertUTF.h" -#include "../../../../common/windows/cpp/include/keymanversion.h" - -bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk); - -#ifdef __EMSCRIPTEN__ -// TODO: move emscripten wrappers into their own .cpp. Also move CompileKeyboardHandle -// into its own .cpp, so CompilerInterfaces.cpp has only C public API functions listed. -// #8889 - -/* - 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(context); - if(buffer == nullptr) { - *bufferSize = wasm_loadfileproc(filename, baseFilename, 0, 0, msgProc); - return *bufferSize != 0; - } 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(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 - std::string kvksFilename; - // 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 = {false}; - KMCMP_COMPILER_RESULT kr; - - r.kmx = 0; - r.kmxSize = 0; - r.kvksFilename = ""; - - 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; - } - - return r; -} - -EMSCRIPTEN_BINDINGS(compiler_interface) { - - emscripten::class_("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_("CompilerInterface") - .constructor<>() - .property("callbacksKey", &WASM_COMPILER_INTERFACE::callbacksKey) - ; - - emscripten::class_("CompilerResult") - .constructor<>() - .property("result", &WASM_COMPILER_RESULT::result) - .property("kmx", &WASM_COMPILER_RESULT::kmx) - .property("kmxSize", &WASM_COMPILER_RESULT::kmxSize) - .property("kvksFilename", &WASM_COMPILER_RESULT::kvksFilename) - ; - - emscripten::function("kmcmp_compile", &kmcmp_wasm_compile); - emscripten::function("kmcmp_parseUnicodeSet", &kmcmp_parseUnicodeSet); -} - -#endif +#include "CompileKeyboardBuffer.h" EXTERN bool kmcmp_CompileKeyboard( const char* pszInfile, @@ -204,7 +79,7 @@ EXTERN bool kmcmp_CompileKeyboard( } kmcmp::CodeConstants = new kmcmp::NamedCodeConstants; - bool success = CompileKeyboardHandle(infile+offset, sz-offset, &fk); + bool success = CompileKeyboardBuffer(infile+offset, sz-offset, &fk); delete kmcmp::CodeConstants; delete[] infile; @@ -233,159 +108,3 @@ EXTERN bool kmcmp_CompileKeyboard( return TRUE; } -bool CompileKeyboardHandle(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk) -{ - PKMX_WCHAR str, p; - - KMX_DWORD msg; - - kmcmp::FMnemonicLayout = FALSE; - - if (!fk) { - AddCompileError(CERR_SomewhereIGotItWrong); - return FALSE; - } - - str = new KMX_WCHAR[LINESIZE]; - if (!str) { - AddCompileError(CERR_CannotAllocateMemory); - return FALSE; - } - - fk->KeyboardID = 0; - fk->version = 0; - fk->dpStoreArray = NULL; - fk->dpGroupArray = NULL; - fk->cxStoreArray = 0; - fk->cxGroupArray = 0; - fk->StartGroup[0] = fk->StartGroup[1] = -1; - fk->szName[0] = 0; - fk->szCopyright[0] = 0; - fk->dwFlags = KF_AUTOMATICVERSION; - fk->currentGroup = 0xFFFFFFFF; - fk->currentStore = 0; - fk->cxDeadKeyArray = 0; - fk->dpDeadKeyArray = NULL; - fk->cxVKDictionary = 0; // I3438 - fk->dpVKDictionary = NULL; // I3438 - fk->extra->kvksFilename = u""; -/* fk->szMessage[0] = 0; - fk->szLanguageName[0] = 0;*/ - fk->dwBitmapSize = 0; - fk->dwHotKey = 0; - - kmcmp::BeginLine[BEGIN_ANSI] = -1; - kmcmp::BeginLine[BEGIN_UNICODE] = -1; - kmcmp::BeginLine[BEGIN_NEWCONTEXT] = -1; - kmcmp::BeginLine[BEGIN_POSTKEYSTROKE] = -1; - - - /* Add a store for the Keyman 6.0 copyright information string */ - - if(kmcmp::FShouldAddCompilerVersion) { - u16sprintf(str,LINESIZE, L"Created with Keyman Developer version %d.%d.%d.%d", KEYMAN_VersionMajor, KEYMAN_VersionMinor, KEYMAN_VersionPatch, 0); - AddStore(fk, TSS_KEYMANCOPYRIGHT, str); - } - - /* Add a system store for the Keyman edition number */ - AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0"); - AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman"); - - int offset = 0; - - // must preprocess for group and store names -> this isn't really necessary, but never mind! - while ((msg = ReadLine(infile, sz, offset, str, TRUE)) == CERR_None) - { - p = str; - switch (LineTokenType(&p)) - { - case T_VERSION: - *(p + 4) = 0; - if ((msg = AddStore(fk, TSS_VERSION, p)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - break; - - case T_GROUP: - if ((msg = ProcessGroupLine(fk, p)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - break; - - case T_STORE: - if ((msg = ProcessStoreLine(fk, p)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - break; - - default: - break; - } - } - - if (msg != CERR_EndOfFile) { - AddCompileError(msg); - return FALSE; - } - - offset = 0; - kmcmp::currentLine = 0; - - /* Reindex the list of codeconstants after stores added */ - - kmcmp::CodeConstants->reindex(); - - /* ReadLine will automatically skip over $Keyman lines, and parse wrapped lines */ - while ((msg = ReadLine(infile, sz, offset, str, FALSE)) == CERR_None) - { - msg = ParseLine(fk, str); - if (msg != CERR_None) { - AddCompileError(msg); - return FALSE; - } - } - - if (msg != CERR_EndOfFile) { - AddCompileError(msg); - return FALSE; - } - - ProcessGroupFinish(fk); - - if (kmcmp::FSaveDebug) kmcmp::RecordDeadkeyNames(fk); - - /* Add the compiler version as a system store */ - if ((msg = kmcmp::AddCompilerVersionStore(fk)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - - if ((msg = BuildVKDictionary(fk)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - - if ((msg = CheckFilenameConsistencyForCalls(fk)) != CERR_None) { - AddCompileError(msg); - return FALSE; - } - - delete str; - - if (!kmcmp::CheckKeyboardFinalVersion(fk)) { - return FALSE; - } - - /* Warn on inconsistent use of NCAPS */ - if (!kmcmp::FMnemonicLayout) { - CheckNCapsConsistency(fk); - } - - /* Flag presence of deprecated features */ - kmcmp::CheckForDeprecatedFeatures(fk); - - return TRUE; -} diff --git a/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp b/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp new file mode 100644 index 0000000000..a20cd9f1b4 --- /dev/null +++ b/developer/src/kmcmplib/src/CompilerInterfacesWasm.cpp @@ -0,0 +1,117 @@ +#include "pch.h" +#include + +#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(context); + if(buffer == nullptr) { + *bufferSize = wasm_loadfileproc(filename, baseFilename, 0, 0, msgProc); + return *bufferSize != 0; + } 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(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 + std::string kvksFilename; + // 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 = {false}; + KMCMP_COMPILER_RESULT kr; + + r.kmx = 0; + r.kmxSize = 0; + r.kvksFilename = ""; + + 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; + } + + return r; +} + +EMSCRIPTEN_BINDINGS(compiler_interface) { + + emscripten::class_("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_("CompilerInterface") + .constructor<>() + .property("callbacksKey", &WASM_COMPILER_INTERFACE::callbacksKey) + ; + + emscripten::class_("CompilerResult") + .constructor<>() + .property("result", &WASM_COMPILER_RESULT::result) + .property("kmx", &WASM_COMPILER_RESULT::kmx) + .property("kmxSize", &WASM_COMPILER_RESULT::kmxSize) + .property("kvksFilename", &WASM_COMPILER_RESULT::kvksFilename) + ; + + emscripten::function("kmcmp_compile", &kmcmp_wasm_compile); + emscripten::function("kmcmp_parseUnicodeSet", &kmcmp_parseUnicodeSet); +} + +#endif diff --git a/developer/src/kmcmplib/src/meson.build b/developer/src/kmcmplib/src/meson.build index e697a0dced..2ca06929bc 100644 --- a/developer/src/kmcmplib/src/meson.build +++ b/developer/src/kmcmplib/src/meson.build @@ -37,8 +37,10 @@ icuuc_dep = icu.get_variable('icuuc_dep') lib = library('kmcmplib', 'CasedKeys.cpp', 'CharToKeyConversion.cpp', + 'CompileKeyboardBuffer.cpp', 'Compiler.cpp', 'CompilerInterfaces.cpp', + 'CompilerInterfacesWasm.cpp', 'DeprecationChecks.cpp', 'Edition.cpp', 'NamedCodeConstants.cpp',