mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-16 05:39:24 +00:00
Merge pull request #8857 from keymanapp/chore/developer/replace-cwrap-with-bind
chore(developer): replace cwrap wasm bindings
This commit is contained in:
commit
8b89ddca5a
6 changed files with 43 additions and 116 deletions
|
|
@ -42,50 +42,10 @@ const baseOptions: CompilerOptions = {
|
|||
*/
|
||||
let callbackProcIdentifier = 0;
|
||||
|
||||
/**
|
||||
* Pointer in wasm-space
|
||||
*/
|
||||
type WasmPtr = number;
|
||||
|
||||
/**
|
||||
* The wrapped functions
|
||||
*/
|
||||
class WasmWrapper {
|
||||
Module: any;
|
||||
|
||||
compileKeyboardFile?: (pszInfile: string, pszOutfile: string, aSaveDebug: number, aCompilerWarningsAsErrors: number, aWarnDeprecatedCode: number, msgProc: string) => boolean;
|
||||
parseUnicodeSet?: (pat: string, buf: WasmPtr, length: number) => number;
|
||||
setCompilerOptions?: (shouldAddCompilerVersion: number) => boolean;
|
||||
|
||||
constructor(wasmModule: any) {
|
||||
this.Module = wasmModule;
|
||||
if (!wasmModule) {
|
||||
throw Error(`wasm host did not load`);
|
||||
}
|
||||
this.compileKeyboardFile = this.Module.cwrap('kmcmp_Wasm_CompileKeyboardFile', 'boolean', ['string', 'string', 'number', 'number', 'number', 'string']);
|
||||
this.parseUnicodeSet = this.Module.cwrap('kmcmp_Wasm_ParseUnicodeSet', 'number', ['string', 'number', 'number']);
|
||||
this.setCompilerOptions = this.Module.cwrap('kmcmp_Wasm_SetCompilerOptions', 'boolean', ['number']);
|
||||
|
||||
if (this.parseUnicodeSet === undefined
|
||||
|| this.setCompilerOptions === undefined
|
||||
|| this.compileKeyboardFile === undefined) {
|
||||
throw Error(`some wasm functions did not load properly.`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point into Wasm functions
|
||||
* @returns WasmWrapper
|
||||
*/
|
||||
public static async load() : Promise<WasmWrapper> {
|
||||
return new WasmWrapper(await loadWasmHost());
|
||||
}
|
||||
};
|
||||
|
||||
export class KmnCompiler {
|
||||
private Module: any;
|
||||
callbackName: string;
|
||||
callbacks: CompilerCallbacks;
|
||||
wasm: WasmWrapper;
|
||||
|
||||
constructor() {
|
||||
this.callbackName = 'kmnCompilerCallback' + callbackProcIdentifier;
|
||||
|
|
@ -94,9 +54,9 @@ export class KmnCompiler {
|
|||
|
||||
public async init(callbacks: CompilerCallbacks): Promise<boolean> {
|
||||
this.callbacks = callbacks;
|
||||
if(!this.wasm) {
|
||||
if(!this.Module) {
|
||||
try {
|
||||
this.wasm = await WasmWrapper.load();
|
||||
this.Module = await loadWasmHost();
|
||||
} catch(e: any) {
|
||||
this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({e}));
|
||||
return false;
|
||||
|
|
@ -114,7 +74,7 @@ export class KmnCompiler {
|
|||
// Can't report a message here.
|
||||
throw Error('Must call Compiler.init(callbacks) before proceeding');
|
||||
}
|
||||
if(!this.wasm) { // fail if wasm not loaded or function not found
|
||||
if(!this.Module) { // fail if wasm not loaded or function not found
|
||||
this.callbacks.reportMessage(CompilerMessages.Fatal_MissingWasmModule({}));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -153,7 +113,7 @@ export class KmnCompiler {
|
|||
|
||||
private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult {
|
||||
let result: CompilerResult = {};
|
||||
let wasm_interface = new this.wasm.Module.CompilerInterface();
|
||||
let wasm_interface = new this.Module.CompilerInterface();
|
||||
let wasm_result = null;
|
||||
try {
|
||||
wasm_interface.saveDebug = options.saveDebug;
|
||||
|
|
@ -161,7 +121,7 @@ export class KmnCompiler {
|
|||
wasm_interface.warnDeprecatedCode = options.warnDeprecatedCode;
|
||||
wasm_interface.messageCallback = this.callbackName;
|
||||
wasm_interface.loadFileCallback = this.callbackName; // TODO: this is wrong, needs to be a new callback; not yet used though
|
||||
wasm_result = this.wasm.Module.kmcmp_compile(infile, wasm_interface);
|
||||
wasm_result = this.Module.kmcmp_compile(infile, wasm_interface);
|
||||
if(!wasm_result.result) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -175,7 +135,7 @@ export class KmnCompiler {
|
|||
|
||||
result.kmx = {
|
||||
filename: outfile,
|
||||
data: new Uint8Array(this.wasm.Module.HEAP8.buffer, wasm_result.kmx, wasm_result.kmxSize)
|
||||
data: new Uint8Array(this.Module.HEAP8.buffer, wasm_result.kmx, wasm_result.kmxSize)
|
||||
};
|
||||
|
||||
return result;
|
||||
|
|
@ -230,16 +190,15 @@ export class KmnCompiler {
|
|||
if (!bufferSize) {
|
||||
bufferSize = 100; // TODO-LDML: Preflight mode? Reuse buffer?
|
||||
}
|
||||
const { Module } = this.wasm;
|
||||
const buf = Module.asm.malloc(bufferSize * 2 * Module.HEAPU32.BYTES_PER_ELEMENT);
|
||||
const buf = this.Module.asm.malloc(bufferSize * 2 * this.Module.HEAPU32.BYTES_PER_ELEMENT);
|
||||
// TODO-LDML: Catch OOM
|
||||
const rc = this.wasm.parseUnicodeSet(pattern, buf, bufferSize);
|
||||
const rc = this.Module.kmcmp_parseUnicodeSet(pattern, buf, bufferSize);
|
||||
if (rc >= 0) {
|
||||
const ranges = [];
|
||||
const startu = (buf / Module.HEAPU32.BYTES_PER_ELEMENT);
|
||||
const startu = (buf / this.Module.HEAPU32.BYTES_PER_ELEMENT);
|
||||
for (let i = 0; i < rc; i++) {
|
||||
const low = Module.HEAPU32[startu + (i * 2) + 0];
|
||||
const high = Module.HEAPU32[startu + (i * 2) + 1];
|
||||
const low = this.Module.HEAPU32[startu + (i * 2) + 0];
|
||||
const high = this.Module.HEAPU32[startu + (i * 2) + 1];
|
||||
ranges.push([low, high]);
|
||||
}
|
||||
// TODO-LDML: no free??
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ EXTERN bool kmcmp_ValidateJsonFile(
|
|||
);
|
||||
|
||||
/**
|
||||
* kmcmp_ParseUnicodeSet is successful if it returns >= USET_OK
|
||||
* kmcmp_parseUnicodeSet is successful if it returns >= USET_OK
|
||||
*/
|
||||
static const int KMCMP_USET_OK = 0;
|
||||
|
||||
|
|
@ -83,24 +83,19 @@ static const int KMCMP_ERROR_UNSUPPORTED_PROPERTY = -3;
|
|||
*/
|
||||
static const int KMCMP_FATAL_OUT_OF_RANGE = -4;
|
||||
|
||||
/**
|
||||
* Function pointer to kmcmp_ParseUnicodeSet
|
||||
*/
|
||||
typedef int (*kmcmp_ParseUnicodeSetProc)(const char* szText, uint32_t* output, uint32_t outputLength);
|
||||
|
||||
/**
|
||||
* Parse a UnicodeSet into 32-bit ranges.
|
||||
* For example, "[]" will return 0 (KMCMP_USET_OK) as a zero-length set.
|
||||
* "[" will return KMCMP_ERROR_SYNTAX_ERR,
|
||||
* and "[x A-C]" will return 2 and [0x41, 0x43, 0x78, 0x78]
|
||||
* @param szText input txt, null terminated, in UTF-8 format
|
||||
* @param text input txt, null terminated, in UTF-8 format
|
||||
* @param outputBuffer output buffer, owned by caller: Pairs of ranges in order
|
||||
* @param outputBufferSize length of output buffer. Needs to be twice the number of expected ranges
|
||||
* @return If >= KMCMP_USET_OK, number of ranges, otherwise one of the negative error values.
|
||||
*/
|
||||
EXTERN int kmcmp_ParseUnicodeSet(
|
||||
const char* szText,
|
||||
uint32_t* outputBuffer,
|
||||
EXTERN int kmcmp_parseUnicodeSet(
|
||||
const std::string text,
|
||||
uintptr_t outputBuffer_,
|
||||
uint32_t outputBufferSize
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -46,39 +46,6 @@ int wasm_CompilerMessageProc(int line, uint32_t dwMsgCode, char* szText, void* c
|
|||
return wasm_msgproc(line, dwMsgCode, szText, msgProc);
|
||||
}
|
||||
|
||||
//DEPRECATED
|
||||
EXTERN bool kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) {
|
||||
KMCMP_COMPILER_OPTIONS options;
|
||||
options.dwSize = sizeof(KMCMP_COMPILER_OPTIONS);
|
||||
options.ShouldAddCompilerVersion = ShouldAddCompilerVersion;
|
||||
return kmcmp_SetCompilerOptions(&options);
|
||||
}
|
||||
|
||||
//DEPRECATED
|
||||
EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile,
|
||||
char* pszOutfile, int ASaveDebug, int ACompilerWarningsAsErrors,
|
||||
int AWarnDeprecatedCode, char* msgProc
|
||||
) {
|
||||
return kmcmp_CompileKeyboardFile(
|
||||
pszInfile,
|
||||
pszOutfile,
|
||||
ASaveDebug,
|
||||
ACompilerWarningsAsErrors,
|
||||
AWarnDeprecatedCode,
|
||||
wasm_CompilerMessageProc,
|
||||
msgProc
|
||||
);
|
||||
}
|
||||
|
||||
EXTERN int kmcmp_Wasm_ParseUnicodeSet(char* pat,
|
||||
uint32_t* buf, int length
|
||||
) {
|
||||
return kmcmp_ParseUnicodeSet(
|
||||
pat, buf, length
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
struct COMPILER_INTERFACE {
|
||||
bool saveDebug;
|
||||
bool compilerWarningsAsErrors;
|
||||
|
|
@ -162,6 +129,7 @@ EMSCRIPTEN_BINDINGS(compiler_interface) {
|
|||
;
|
||||
|
||||
emscripten::function("kmcmp_compile", &kmcmp_compile);
|
||||
emscripten::function("kmcmp_parseUnicodeSet", &kmcmp_parseUnicodeSet);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ endif
|
|||
name_suffix = []
|
||||
|
||||
if cpp_compiler.get_id() == 'emscripten'
|
||||
links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'cwrap\', \'UTF8ToString\']']
|
||||
links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'UTF8ToString\']']
|
||||
# tests are building as ES6 so we need to declare the file extension
|
||||
# note that meson currently struggles with the sanitycheckc_cross.exe
|
||||
# program, because it has a hard coded extension (.exe) which is not
|
||||
|
|
|
|||
|
|
@ -4,16 +4,13 @@
|
|||
#include "unicode/uniset.h"
|
||||
#include "unicode/unistr.h"
|
||||
|
||||
EXTERN int kmcmp_ParseUnicodeSet(
|
||||
const char* szText,
|
||||
uint32_t* outputBuffer,
|
||||
EXTERN int kmcmp_parseUnicodeSet(
|
||||
const std::string text,
|
||||
uintptr_t outputBuffer_,
|
||||
uint32_t outputBufferSize
|
||||
) {
|
||||
if (szText == nullptr) {
|
||||
// null string coming in
|
||||
return KMCMP_ERROR_SYNTAX_ERR;
|
||||
}
|
||||
const icu::UnicodeString str = icu::UnicodeString::fromUTF8(szText);
|
||||
uint32_t* outputBuffer = reinterpret_cast<uint32_t*>(outputBuffer_);
|
||||
const icu::UnicodeString str = icu::UnicodeString::fromUTF8(text.c_str());
|
||||
if (str.isBogus() || str.isEmpty()) {
|
||||
// empty string
|
||||
return KMCMP_ERROR_SYNTAX_ERR;
|
||||
|
|
|
|||
|
|
@ -19,30 +19,32 @@
|
|||
#include "../src/compfile.h"
|
||||
#include <test_assert.h>
|
||||
|
||||
void test_kmcmp_ParseUnicodeSetProc();
|
||||
void test_kmcmp_parseUnicodeSet();
|
||||
|
||||
// std::vector<int> error_vec;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_kmcmp_ParseUnicodeSetProc();
|
||||
test_kmcmp_parseUnicodeSet();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void test_kmcmp_ParseUnicodeSetProc() {
|
||||
void test_kmcmp_parseUnicodeSet() {
|
||||
{
|
||||
// null test
|
||||
const auto bufsiz = 128;
|
||||
uint32_t buf[bufsiz];
|
||||
int rc = kmcmp_ParseUnicodeSet(u8"[]", buf, bufsiz);
|
||||
uintptr_t buf_ = reinterpret_cast<uintptr_t>(buf);
|
||||
int rc = kmcmp_parseUnicodeSet(u8"[]", buf_, bufsiz);
|
||||
assert(rc == KMCMP_USET_OK);
|
||||
}
|
||||
{
|
||||
// basic test
|
||||
const auto bufsiz = 128;
|
||||
uint32_t buf[bufsiz];
|
||||
int rc = kmcmp_ParseUnicodeSet(u8"[x A-C]", buf, bufsiz);
|
||||
uintptr_t buf_ = reinterpret_cast<uintptr_t>(buf);
|
||||
int rc = kmcmp_parseUnicodeSet(u8"[x A-C]", buf_, bufsiz);
|
||||
assert(rc == 2);
|
||||
assert(buf[0] == 0x41);
|
||||
assert(buf[1] == 0x43);
|
||||
|
|
@ -53,7 +55,8 @@ void test_kmcmp_ParseUnicodeSetProc() {
|
|||
// bigger test
|
||||
const auto bufsiz = 128;
|
||||
uint32_t buf[bufsiz];
|
||||
int rc = kmcmp_ParseUnicodeSet(u8"[[🙀A-C]-[CB]]", buf, bufsiz);
|
||||
uintptr_t buf_ = reinterpret_cast<uintptr_t>(buf);
|
||||
int rc = kmcmp_parseUnicodeSet(u8"[[🙀A-C]-[CB]]", buf_, bufsiz);
|
||||
assert(rc == 2);
|
||||
assert(buf[0] == 0x41);
|
||||
assert(buf[1] == 0x41);
|
||||
|
|
@ -64,35 +67,40 @@ void test_kmcmp_ParseUnicodeSetProc() {
|
|||
// overflow test
|
||||
const auto bufsiz = 1;
|
||||
uint32_t buf[bufsiz];
|
||||
int rc = kmcmp_ParseUnicodeSet(u8"[x A-C]", buf, bufsiz);
|
||||
uintptr_t buf_ = reinterpret_cast<uintptr_t>(buf);
|
||||
int rc = kmcmp_parseUnicodeSet(u8"[x A-C]", buf_, bufsiz);
|
||||
assert(rc == KMCMP_FATAL_OUT_OF_RANGE);
|
||||
}
|
||||
{
|
||||
// err test
|
||||
const auto bufsiz = 128;
|
||||
uint32_t buf[bufsiz];
|
||||
int rc = kmcmp_ParseUnicodeSet(u8"[:Adlm:]", buf, bufsiz);
|
||||
uintptr_t buf_ = reinterpret_cast<uintptr_t>(buf);
|
||||
int rc = kmcmp_parseUnicodeSet(u8"[:Adlm:]", buf_, bufsiz);
|
||||
assert(rc == KMCMP_ERROR_UNSUPPORTED_PROPERTY);
|
||||
}
|
||||
{
|
||||
// err test
|
||||
const auto bufsiz = 128;
|
||||
uint32_t buf[bufsiz];
|
||||
int rc = kmcmp_ParseUnicodeSet(u8"[[\\p{Mn}]&[A-Z]]", buf, bufsiz);
|
||||
uintptr_t buf_ = reinterpret_cast<uintptr_t>(buf);
|
||||
int rc = kmcmp_parseUnicodeSet(u8"[[\\p{Mn}]&[A-Z]]", buf_, bufsiz);
|
||||
assert(rc == KMCMP_ERROR_UNSUPPORTED_PROPERTY);
|
||||
}
|
||||
{
|
||||
// err test
|
||||
const auto bufsiz = 128;
|
||||
uint32_t buf[bufsiz];
|
||||
int rc = kmcmp_ParseUnicodeSet(u8"[abc{def}]", buf, bufsiz);
|
||||
uintptr_t buf_ = reinterpret_cast<uintptr_t>(buf);
|
||||
int rc = kmcmp_parseUnicodeSet(u8"[abc{def}]", buf_, bufsiz);
|
||||
assert(rc == KMCMP_ERROR_HAS_STRINGS);
|
||||
}
|
||||
{
|
||||
// err test
|
||||
const auto bufsiz = 128;
|
||||
uint32_t buf[bufsiz];
|
||||
int rc = kmcmp_ParseUnicodeSet(u8"[[]", buf, bufsiz);
|
||||
uintptr_t buf_ = reinterpret_cast<uintptr_t>(buf);
|
||||
int rc = kmcmp_parseUnicodeSet(u8"[[]", buf_, bufsiz);
|
||||
assert(rc == KMCMP_ERROR_SYNTAX_ERR);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue