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.
This commit is contained in:
Marc Durdin 2023-06-01 05:29:19 +07:00
parent 9d351f4798
commit c3ecae4e98
5 changed files with 292 additions and 283 deletions

View file

@ -0,0 +1,166 @@
#include "pch.h"
#include <kmn_compiler_errors.h>
#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;
}

View file

@ -0,0 +1,5 @@
#pragma once
#include "compfile.h"
bool CompileKeyboardBuffer(KMX_BYTE* infile, int sz, PFILE_KEYBOARD fk);

View file

@ -1,134 +1,9 @@
#include "pch.h"
#include <kmcmplibapi.h>
#include <kmn_compiler_errors.h>
#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<char*>(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<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
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_<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("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;
}

View file

@ -0,0 +1,117 @@
#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 != 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<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
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_<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("kvksFilename", &WASM_COMPILER_RESULT::kvksFilename)
;
emscripten::function("kmcmp_compile", &kmcmp_wasm_compile);
emscripten::function("kmcmp_parseUnicodeSet", &kmcmp_parseUnicodeSet);
}
#endif

View file

@ -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',