Merge pull request #8857 from keymanapp/chore/developer/replace-cwrap-with-bind

chore(developer): replace cwrap wasm bindings
This commit is contained in:
Marc Durdin 2023-05-31 13:28:21 +10:00 committed by GitHub
commit 8b89ddca5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 116 deletions

View file

@ -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??

View file

@ -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
);

View file

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

View file

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

View file

@ -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;

View file

@ -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);
}
}