mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-06 14:07:32 +00:00
Merge pull request #8850 from keymanapp/refactor/developer/wasm-compiler-interface
refactor(developer): compiler interface part 1 for wasm
This commit is contained in:
commit
18c4ac5bb2
16 changed files with 389 additions and 196 deletions
Binary file not shown.
Binary file not shown.
|
|
@ -35,10 +35,17 @@ export default class KVKSFileReader {
|
|||
|
||||
parser.parseString(file, (e: unknown, r: unknown) => { source = r as KVKSourceFile });
|
||||
source = this.boxArrays(source);
|
||||
this.cleanupFlags(source);
|
||||
this.cleanupUnderscore('visualkeyboard', source.visualkeyboard);
|
||||
return source;
|
||||
}
|
||||
|
||||
private cleanupFlags(source: any) {
|
||||
if(source.visualkeyboard?.header?.flags === '') {
|
||||
source.visualkeyboard.header.flags = {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The only element that allows spaces is <key>. Remove
|
||||
* all other empty whitespace-only values.
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ export interface CompilerFileSystemCallbacks {
|
|||
readFileSync(path: string, options?: { encoding?: null; flag?: string; } | null): Uint8Array;
|
||||
readFileSync(path: string, options: { encoding: string; flag?: string; } | string): string;
|
||||
readFileSync(path: string, options?: { encoding?: string | null; flag?: string; } | string | null): string | Uint8Array;
|
||||
writeFileSync(path: string, data: Uint8Array): void;
|
||||
|
||||
existsSync(name: string): boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ type
|
|||
dpDeadKeyArray: PFILE_DEADKEY; // temp - dead key array
|
||||
cxVKDictionary: DWORD; // I3438
|
||||
dpVKDictionary: PFILE_VKDICTIONARY; // I3438 // temp - virtual key dictionary
|
||||
|
||||
extra: Pointer;
|
||||
end;
|
||||
|
||||
PFILE_KEYBOARD = ^FILE_KEYBOARD;
|
||||
|
|
@ -152,13 +154,13 @@ const
|
|||
const
|
||||
// kcframe --sizeof returns these values
|
||||
{$IFDEF WIN64}
|
||||
FILE_KEYBOARD_SIZE = 2984;
|
||||
FILE_KEYBOARD_SIZE = 2992;
|
||||
FILE_GROUP_SIZE = 200;
|
||||
FILE_STORE_SIZE = 200;
|
||||
FILE_KEY_SIZE = 32;
|
||||
FILE_DEADKEY_SIZE = 160;
|
||||
{$ELSE}
|
||||
FILE_KEYBOARD_SIZE = 2952;
|
||||
FILE_KEYBOARD_SIZE = 2956;
|
||||
FILE_GROUP_SIZE = 188;
|
||||
FILE_STORE_SIZE = 192;
|
||||
FILE_KEY_SIZE = 20;
|
||||
|
|
|
|||
|
|
@ -1,31 +1,26 @@
|
|||
/*
|
||||
TODO: implement additional interfaces:
|
||||
|
||||
extern "C" bool kmcmp_CompileKeyboardFileToBuffer(
|
||||
char* pszInfile,
|
||||
void* pfkBuffer,
|
||||
bool ACompilerWarningsAsErrors,
|
||||
bool AWarnDeprecatedCode,
|
||||
kmcmp_CompilerMessageProc pMsgproc,
|
||||
void* AmsgprocContext,
|
||||
int Target
|
||||
);
|
||||
|
||||
typedef bool (*kmcmp_ValidateJsonMessageProc)(int64_t offset, const char* szText, void* context);
|
||||
|
||||
extern "C" bool kmcmp_ValidateJsonFile(
|
||||
std::fstream& f,
|
||||
std::fstream& fd,
|
||||
kmcmp_ValidateJsonMessageProc MessageProc,
|
||||
void* context
|
||||
);
|
||||
typedef bool (*kmcmp_ValidateJsonMessageProc)();
|
||||
extern "C" bool kmcmp_ValidateJsonFile();
|
||||
*/
|
||||
|
||||
// TODO: rename wasm-host?
|
||||
import { CompilerCallbacks, CompilerEvent } from '@keymanapp/common-types';
|
||||
import { CompilerCallbacks, CompilerEvent, KvkFileWriter, KvksFileReader } from '@keymanapp/common-types';
|
||||
import loadWasmHost from '../import/kmcmplib/wasm-host.js';
|
||||
import { CompilerMessages, mapErrorFromKmcmplib } from './messages.js';
|
||||
|
||||
export interface CompilerResultFile {
|
||||
filename: string;
|
||||
data: Uint8Array;
|
||||
};
|
||||
|
||||
export interface CompilerResult {
|
||||
kmx?: CompilerResultFile;
|
||||
kvk?: CompilerResultFile;
|
||||
js?: CompilerResultFile;
|
||||
};
|
||||
|
||||
export interface CompilerOptions {
|
||||
shouldAddCompilerVersion?: boolean;
|
||||
saveDebug?: boolean;
|
||||
|
|
@ -136,7 +131,19 @@ export class KmnCompiler {
|
|||
// TODO: use callbacks for file access -- so kmc-kmn is entirely fs agnostic
|
||||
let result = this.runCompiler(infile, outfile, options);
|
||||
delete (globalThis as any)[this.callbackName];
|
||||
return result;
|
||||
//TODO: write the file out!
|
||||
if(result) {
|
||||
if(result.kmx) {
|
||||
this.callbacks.fs.writeFileSync(result.kmx.filename, result.kmx.data);
|
||||
}
|
||||
if(result.kvk) {
|
||||
this.callbacks.fs.writeFileSync(result.kvk.filename, result.kvk.data);
|
||||
}
|
||||
if(result.js) {
|
||||
this.callbacks.fs.writeFileSync(result.js.filename, result.js.data);
|
||||
}
|
||||
}
|
||||
return !!result;
|
||||
}
|
||||
|
||||
private compilerMessageCallback = (line: number, code: number, msg: string): number => {
|
||||
|
|
@ -144,24 +151,71 @@ export class KmnCompiler {
|
|||
return 1;
|
||||
}
|
||||
|
||||
private runCompiler(infile: string, outfile: string, options: CompilerOptions): boolean {
|
||||
private runCompiler(infile: string, outfile: string, options: CompilerOptions): CompilerResult {
|
||||
let result: CompilerResult = {};
|
||||
let wasm_interface = new this.wasm.Module.CompilerInterface();
|
||||
let wasm_result = null;
|
||||
try {
|
||||
if (!this.wasm.setCompilerOptions(options.shouldAddCompilerVersion ? 1 : 0)) {
|
||||
this.callbacks.reportMessage(CompilerMessages.Fatal_UnableToSetCompilerOptions());
|
||||
wasm_interface.saveDebug = options.saveDebug;
|
||||
wasm_interface.compilerWarningsAsErrors = options.compilerWarningsAsErrors;
|
||||
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);
|
||||
if(!wasm_result.result) {
|
||||
return null;
|
||||
}
|
||||
return this.wasm.compileKeyboardFile(
|
||||
infile,
|
||||
outfile,
|
||||
options.saveDebug ? 1 : 0,
|
||||
options.compilerWarningsAsErrors ? 1 : 0,
|
||||
options.warnDeprecatedCode ? 1 : 0,
|
||||
this.callbackName);
|
||||
|
||||
if(wasm_result.kvksFilename) {
|
||||
result.kvk = this.runKvkCompiler(wasm_result.kvksFilename, infile, outfile);
|
||||
if(!result.kvk) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
result.kmx = {
|
||||
filename: outfile,
|
||||
data: new Uint8Array(this.wasm.Module.HEAP8.buffer, wasm_result.kmx, wasm_result.kmxSize)
|
||||
};
|
||||
|
||||
return result;
|
||||
} catch(e) {
|
||||
this.callbacks.reportMessage(CompilerMessages.Fatal_UnexpectedException({e:e}));
|
||||
return false;
|
||||
return null;
|
||||
} finally {
|
||||
if(wasm_result) {
|
||||
wasm_result.delete();
|
||||
}
|
||||
wasm_interface.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private runKvkCompiler(kvksFilename: string, kmnFilename: string, kmxFilename: string) {
|
||||
// The compiler detected a .kvks file, which needs to be captured
|
||||
let reader = new KvksFileReader();
|
||||
kvksFilename = this.callbacks.resolveFilename(kmnFilename, kvksFilename);
|
||||
let kvks = reader.read(this.callbacks.loadFile(kvksFilename));
|
||||
try {
|
||||
reader.validate(kvks, this.callbacks.loadSchema('kvks'));
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
// TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e}));
|
||||
return null;
|
||||
}
|
||||
let errors: any = []; //TODO: KVKSParseError[];
|
||||
let vk = reader.transform(kvks, errors);
|
||||
if(!vk || errors.length) {
|
||||
console.dir(errors);
|
||||
// TODO: this.callbacks.reportMessage(CompilerMessages.Error_InvalidKvksFile({e}));
|
||||
return null;
|
||||
}
|
||||
let writer = new KvkFileWriter();
|
||||
return {
|
||||
filename: this.callbacks.path.join(this.callbacks.path.dirname(kmxFilename), this.callbacks.path.basename(kvksFilename, '.kvks') + '.kvk'),
|
||||
data: writer.write(vk)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pattern UnicodeSet pattern such as `[a-z]`
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import 'mocha';
|
||||
import sinon from 'sinon';
|
||||
import chai, { assert } from 'chai';
|
||||
import sinonChai from 'sinon-chai';
|
||||
import { assert } from 'chai';
|
||||
import { KmnCompiler } from '../src/main.js';
|
||||
import { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
|
@ -9,21 +7,10 @@ import fs from 'fs';
|
|||
import { TestCompilerCallbacks } from '@keymanapp/developer-test-helpers';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url)).replace(/\\/g, '/');
|
||||
const baselineDir = __dirname + '/../../../../../common/test/keyboards/baseline/';
|
||||
chai.use(sinonChai);
|
||||
const keyboardsDir = __dirname + '/../../../../../common/test/keyboards/';
|
||||
const baselineDir = keyboardsDir + 'baseline/';
|
||||
|
||||
describe('Compiler class', function() {
|
||||
let consoleLog: any;
|
||||
|
||||
// TODO: do we need this?
|
||||
beforeEach(function() {
|
||||
consoleLog = sinon.spy(console, 'log');
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
consoleLog.restore();
|
||||
});
|
||||
|
||||
it('should throw on failure', async function() {
|
||||
const compiler = new KmnCompiler();
|
||||
const callbacks : any = null; // ERROR
|
||||
|
|
@ -87,4 +74,35 @@ describe('Compiler class', function() {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should compile a keyboard with visual keyboard', async function() {
|
||||
const compiler = new KmnCompiler();
|
||||
const callbacks = new TestCompilerCallbacks();
|
||||
assert(await compiler.init(callbacks));
|
||||
assert(compiler.verifyInitialized());
|
||||
|
||||
const fixtureDir = keyboardsDir + 'caps_lock_layer_3620/'
|
||||
const infile = fixtureDir + 'source/caps_lock_layer_3620.kmn';
|
||||
const kmxFixture = fixtureDir + '/binary/caps_lock_layer_3620.kmx';
|
||||
const kvkFixture = fixtureDir + '/binary/caps_lock_layer_3620.kvk';
|
||||
|
||||
const kmxfile = __dirname + '/caps_lock_layer_3620.kmx';
|
||||
const kvkfile = __dirname + '/caps_lock_layer_3620.kvk';
|
||||
|
||||
assert(compiler.run(infile, kmxfile, {saveDebug: true, shouldAddCompilerVersion: false}));
|
||||
|
||||
assert(fs.existsSync(kmxfile));
|
||||
assert(fs.existsSync(kvkfile));
|
||||
|
||||
const kmxData = fs.readFileSync(kmxfile);
|
||||
const kmxFixtureData = fs.readFileSync(kmxFixture);
|
||||
assert.equal(kmxData.byteLength, kmxFixtureData.byteLength);
|
||||
assert.deepEqual(kmxData, kmxFixtureData);
|
||||
|
||||
const kvkData = fs.readFileSync(kvkfile);
|
||||
const kvkFixtureData = fs.readFileSync(kvkFixture);
|
||||
assert.equal(kvkData.byteLength, kvkFixtureData.byteLength);
|
||||
assert.deepEqual(kvkData, kvkFixtureData);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,6 +22,13 @@
|
|||
|
||||
#include "../../../common/windows/cpp/include/legacy_kmx_file.h"
|
||||
|
||||
|
||||
// This file is deprecated; see kmcmplib/src/compfile.h. However, as long as
|
||||
// this file continues to live, we need to keep structures in it in exact sync
|
||||
// with kmcmplib/src/compfile.h, as FILE_KEYBOARD is passed between kmcmplib and
|
||||
// kmcmpdll. KMX_WCHAR on Windows is identical to wchar_t, so it is safe to map
|
||||
// accordingly.
|
||||
|
||||
#define LINESIZE 8192
|
||||
#define GLOBAL_BUFSIZE 4096
|
||||
|
||||
|
|
@ -70,9 +77,9 @@
|
|||
enum FileStoreType { FST_STORE, FST_OPTION, FST_RESERVED };
|
||||
|
||||
struct FILE_STORE {
|
||||
DWORD dwSystemID;
|
||||
WCHAR szName[SZMAX_STORENAME]; // the name of the store
|
||||
PWSTR dpString; // from start of store structure
|
||||
DWORD dwSystemID;
|
||||
WCHAR szName[SZMAX_STORENAME]; // the name of the store
|
||||
PWSTR dpString; // from start of store structure
|
||||
//FileStoreType fstType;
|
||||
BOOL fIsStore;
|
||||
BOOL fIsReserved;
|
||||
|
|
@ -80,77 +87,75 @@ struct FILE_STORE {
|
|||
BOOL fIsDebug;
|
||||
BOOL fIsCall;
|
||||
int line; // TODO: int vs dword, line vs Line (see FILE_KEY, FILE_GROUP)
|
||||
};
|
||||
};
|
||||
|
||||
typedef FILE_STORE *PFILE_STORE;
|
||||
|
||||
struct FILE_KEY {
|
||||
WCHAR Key; // WCHAR for consistency; only a byte used however
|
||||
WORD LineStoreIndex;
|
||||
DWORD Line;
|
||||
DWORD ShiftFlags;
|
||||
PWSTR dpOutput; // from start of key structure
|
||||
PWSTR dpContext; // from start of key structure
|
||||
};
|
||||
|
||||
WCHAR Key; // WCHAR for consistency; only a byte used however
|
||||
WORD LineStoreIndex;
|
||||
DWORD Line;
|
||||
DWORD ShiftFlags;
|
||||
PWSTR dpOutput; // from start of key structure
|
||||
PWSTR dpContext; // from start of key structure
|
||||
};
|
||||
typedef FILE_KEY *PFILE_KEY;
|
||||
|
||||
struct FILE_GROUP {
|
||||
WCHAR szName[SZMAX_GROUPNAME];
|
||||
PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure
|
||||
PWSTR dpMatch; // from start of group structure
|
||||
PWSTR dpNoMatch; // from start of group structure
|
||||
DWORD cxKeyArray; // in array items
|
||||
BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
|
||||
WCHAR szName[SZMAX_GROUPNAME];
|
||||
PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure
|
||||
PWSTR dpMatch; // from start of group structure
|
||||
PWSTR dpNoMatch; // from start of group structure
|
||||
DWORD cxKeyArray; // in array items
|
||||
BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
|
||||
BOOL fReadOnly; // group(xx) [readonly] <-- specified or not
|
||||
DWORD Line;
|
||||
};
|
||||
|
||||
typedef FILE_GROUP *PFILE_GROUP;
|
||||
|
||||
struct FILE_DEADKEY
|
||||
{
|
||||
WCHAR szName[SZMAX_DEADKEYNAME];
|
||||
struct FILE_DEADKEY {
|
||||
WCHAR szName[SZMAX_DEADKEYNAME];
|
||||
};
|
||||
|
||||
typedef FILE_DEADKEY *PFILE_DEADKEY;
|
||||
|
||||
struct FILE_VKDICTIONARY
|
||||
{
|
||||
struct FILE_VKDICTIONARY {
|
||||
WCHAR szName[SZMAX_VKDICTIONARYNAME];
|
||||
};
|
||||
|
||||
typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY;
|
||||
|
||||
struct FILE_KEYBOARD {
|
||||
DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts
|
||||
DWORD KeyboardID; // deprecated, unused
|
||||
|
||||
DWORD version; // keyboard file version with VERSION keyword
|
||||
DWORD version; // keyboard file version with VERSION keyword
|
||||
|
||||
PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure
|
||||
PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure
|
||||
PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure
|
||||
PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure
|
||||
|
||||
DWORD cxStoreArray; // in number of items
|
||||
DWORD cxGroupArray; // in number of items
|
||||
DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1]
|
||||
DWORD cxStoreArray; // in number of items
|
||||
DWORD cxGroupArray; // in number of items
|
||||
DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1]
|
||||
|
||||
DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)
|
||||
DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)
|
||||
|
||||
WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name
|
||||
WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name
|
||||
WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information
|
||||
WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard
|
||||
PBYTE lpBitmap;
|
||||
DWORD dwBitmapSize;
|
||||
DWORD dwFlags; // Flags for the keyboard file
|
||||
WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name
|
||||
WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name
|
||||
WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information
|
||||
WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard
|
||||
PBYTE lpBitmap;
|
||||
DWORD dwBitmapSize;
|
||||
DWORD dwFlags; // Flags for the keyboard file
|
||||
|
||||
DWORD currentGroup; // temp - current processing group
|
||||
DWORD currentStore; // temp - current processing store
|
||||
DWORD cxDeadKeyArray;
|
||||
PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array
|
||||
DWORD currentGroup; // temp - current processing group
|
||||
DWORD currentStore; // temp - current processing store
|
||||
DWORD cxDeadKeyArray;
|
||||
PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array
|
||||
DWORD cxVKDictionary;
|
||||
PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary
|
||||
};
|
||||
|
||||
void* extra; // used by kmcmplib and its consumers; unused in kmcmpdll
|
||||
};
|
||||
|
||||
typedef FILE_KEYBOARD *PFILE_KEYBOARD;
|
||||
|
||||
|
|
@ -168,34 +173,34 @@ const DWORD sz_FILE_VKDICTIONARY = sizeof(FILE_VKDICTIONARY);
|
|||
const DWORD sz_FILE_KEYBOARD = sizeof(FILE_KEYBOARD);
|
||||
|
||||
struct COMPMSG {
|
||||
char szText[SZMAX_ERRORTEXT];
|
||||
DWORD Line;
|
||||
DWORD dwMsgCode;
|
||||
};
|
||||
char szText[SZMAX_ERRORTEXT];
|
||||
DWORD Line;
|
||||
DWORD dwMsgCode;
|
||||
};
|
||||
|
||||
typedef COMPMSG *PCOMPMSG;
|
||||
|
||||
struct COMPILEMESSAGES {
|
||||
int nMessages;
|
||||
int nErrors;
|
||||
int nMessages;
|
||||
int nErrors;
|
||||
|
||||
PCOMPMSG cm;
|
||||
PCOMPMSG cm;
|
||||
|
||||
DWORD fatalCode;
|
||||
char szFatalText[SZMAX_ERRORTEXT];
|
||||
DWORD fatalCode;
|
||||
char szFatalText[SZMAX_ERRORTEXT];
|
||||
|
||||
DWORD currentLine;
|
||||
};
|
||||
DWORD currentLine;
|
||||
};
|
||||
|
||||
typedef COMPILEMESSAGES *PCOMPILEMESSAGES;
|
||||
|
||||
/*
|
||||
struct TVersion
|
||||
{
|
||||
//int MinVersion; // 0x0500 usually
|
||||
//int CompilerVersion[4];
|
||||
//int MinCompilerVersion[4];
|
||||
int KeyboardVersion; // 0x0500 usually
|
||||
//int MinVersion; // 0x0500 usually
|
||||
//int CompilerVersion[4];
|
||||
//int MinCompilerVersion[4];
|
||||
int KeyboardVersion; // 0x0500 usually
|
||||
};
|
||||
|
||||
extern TVersion FVersionInfo;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include <compfile.h>
|
||||
|
||||
extern "C" BOOL CompileKeyboardFile(PSTR pszInfile, PSTR pszOutfile, BOOL FSaveDebug, BOOL ACompilerWarningsAsErrors, BOOL AWarnDeprecatedCode, CompilerMessageProc pMsgProc); // I4865 // I4866
|
||||
|
||||
int WINAPI msgproc(int line, DWORD dwMsgCode, LPSTR szText)
|
||||
{
|
||||
printf("line %d error %x %s\n", line, (unsigned int) dwMsgCode, szText);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/bind.h>
|
||||
|
||||
#else
|
||||
#define EMSCRIPTEN_KEEPALIVE
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ project('kmcmplib', 'cpp', 'c',
|
|||
default_options : ['buildtype=release',
|
||||
'cpp_std=c++14',
|
||||
'b_vscrt=static_from_buildtype',
|
||||
'default_library=static'])
|
||||
'default_library=static',
|
||||
'debug=true'])
|
||||
|
||||
# Import our standard compiler defines; this is copied from
|
||||
# /resources/build/standard.meson.build by build.sh, because
|
||||
|
|
|
|||
|
|
@ -784,7 +784,7 @@ KMX_DWORD ProcessStoreLine(PFILE_KEYBOARD fk, PKMX_WCHAR p)
|
|||
return CheckForDuplicateStore(fk, sp);
|
||||
}
|
||||
|
||||
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, KMX_WCHAR const * str, KMX_DWORD *dwStoreID)
|
||||
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, const KMX_WCHAR * str, KMX_DWORD *dwStoreID)
|
||||
{
|
||||
PFILE_STORE sp;
|
||||
sp = new FILE_STORE[fk->cxStoreArray + 1];
|
||||
|
|
@ -1023,6 +1023,9 @@ KMX_DWORD ProcessSystemStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, PFILE_STORE
|
|||
case TSS_VISUALKEYBOARD:
|
||||
VERIFY_KEYBOARD_VERSION(fk, VERSION_70, CERR_70FeatureOnly);
|
||||
{
|
||||
// Store extra metadata for callers as we mutate this store during
|
||||
// compilation
|
||||
fk->extra->kvksFilename = sp->dpString;
|
||||
// Strip path from the store, leaving bare filename only
|
||||
p = sp->dpString;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
#define SetError(err) { if(AddCompileError(err) || (err & CERR_FATAL)) return FALSE; }
|
||||
|
||||
bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk);
|
||||
bool CompileKeyboard(const char* pszInfile,
|
||||
void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors,
|
||||
bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, const void* AmsgprocContext,
|
||||
int Target);
|
||||
|
||||
EXTERN bool kmcmp_SetCompilerOptions(KMCMP_COMPILER_OPTIONS* options) {
|
||||
//printf("°°-> changed to SetCompilerOptions() of kmcmplib \n");
|
||||
|
|
@ -44,6 +48,7 @@ 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);
|
||||
|
|
@ -51,6 +56,7 @@ EXTERN bool kmcmp_Wasm_SetCompilerOptions(int ShouldAddCompilerVersion) {
|
|||
return kmcmp_SetCompilerOptions(&options);
|
||||
}
|
||||
|
||||
//DEPRECATED
|
||||
EXTERN bool kmcmp_Wasm_CompileKeyboardFile(char* pszInfile,
|
||||
char* pszOutfile, int ASaveDebug, int ACompilerWarningsAsErrors,
|
||||
int AWarnDeprecatedCode, char* msgProc
|
||||
|
|
@ -74,11 +80,97 @@ EXTERN int kmcmp_Wasm_ParseUnicodeSet(char* pat,
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
struct COMPILER_INTERFACE {
|
||||
bool saveDebug;
|
||||
bool compilerWarningsAsErrors;
|
||||
bool warnDeprecatedCode;
|
||||
bool shouldAddCompilerVersion;
|
||||
int target; // CKF_KEYMAN, CKF_KEYMANWEB
|
||||
std::string messageCallback; // int line, uint32_t dwMsgCode, char* szText
|
||||
std::string loadFileCallback; // char* infile, char* filenameRelativeToInfile --> buffer
|
||||
};
|
||||
|
||||
struct 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
|
||||
};
|
||||
|
||||
COMPILER_RESULT kmcmp_compile(std::string pszInfile, const COMPILER_INTERFACE intf) {
|
||||
COMPILER_RESULT r = {false};
|
||||
|
||||
FILE_KEYBOARD fk;
|
||||
|
||||
// TODO: this should be included in CompileKeyboard?
|
||||
kmcmp::FShouldAddCompilerVersion = intf.shouldAddCompilerVersion;
|
||||
|
||||
r.result = CompileKeyboard(
|
||||
pszInfile.c_str(),
|
||||
&fk,
|
||||
intf.saveDebug,
|
||||
intf.compilerWarningsAsErrors,
|
||||
intf.warnDeprecatedCode,
|
||||
wasm_CompilerMessageProc,
|
||||
intf.messageCallback.c_str(),
|
||||
intf.target);
|
||||
|
||||
if(!r.result) {
|
||||
return r;
|
||||
}
|
||||
|
||||
KMX_DWORD msg;
|
||||
KMX_BYTE* data = nullptr;
|
||||
size_t dataSize = 0;
|
||||
msg = WriteCompiledKeyboard(&fk, &data, dataSize);
|
||||
//TODO: FreeKeyboardPointers(fk);
|
||||
|
||||
if(msg != CERR_None) {
|
||||
AddCompileError(msg);
|
||||
r.result = FALSE;
|
||||
return r;
|
||||
}
|
||||
|
||||
r.kmx = (int) data;
|
||||
r.kmxSize = (int) dataSize;
|
||||
r.kvksFilename = string_from_u16string(fk.extra->kvksFilename); // convert to UTF8
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_BINDINGS(compiler_interface) {
|
||||
emscripten::class_<COMPILER_INTERFACE>("CompilerInterface")
|
||||
.constructor<>()
|
||||
.property("saveDebug", &COMPILER_INTERFACE::saveDebug)
|
||||
.property("compilerWarningsAsErrors", &COMPILER_INTERFACE::compilerWarningsAsErrors)
|
||||
.property("warnDeprecatedCode", &COMPILER_INTERFACE::warnDeprecatedCode)
|
||||
.property("shouldAddCompilerVersion", &COMPILER_INTERFACE::shouldAddCompilerVersion)
|
||||
.property("target", &COMPILER_INTERFACE::target)
|
||||
.property("messageCallback", &COMPILER_INTERFACE::messageCallback)
|
||||
.property("loadFileCallback", &COMPILER_INTERFACE::loadFileCallback)
|
||||
;
|
||||
|
||||
emscripten::class_<COMPILER_RESULT>("CompilerResult")
|
||||
.constructor<>()
|
||||
.property("result", &COMPILER_RESULT::result)
|
||||
.property("kmx", &COMPILER_RESULT::kmx)
|
||||
.property("kmxSize", &COMPILER_RESULT::kmxSize)
|
||||
.property("kvksFilename", &COMPILER_RESULT::kvksFilename)
|
||||
;
|
||||
|
||||
emscripten::function("kmcmp_compile", &kmcmp_compile);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool CompileKeyboard(char* pszInfile,
|
||||
bool CompileKeyboard(const char* pszInfile,
|
||||
void* pfkBuffer, bool ASaveDebug, bool ACompilerWarningsAsErrors,
|
||||
bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, void* AmsgprocContext,
|
||||
bool AWarnDeprecatedCode, kmcmp_CompilerMessageProc pMsgproc, const void* AmsgprocContext,
|
||||
int Target) {
|
||||
|
||||
FILE* fp_in = NULL;
|
||||
|
|
@ -95,7 +187,7 @@ bool CompileKeyboard(char* pszInfile,
|
|||
|
||||
PKMX_STR p;
|
||||
|
||||
if ((p = strrchr_slash(pszInfile)) != nullptr)
|
||||
if ((p = strrchr_slash((char*)pszInfile)) != nullptr)
|
||||
{
|
||||
strncpy(kmcmp::CompileDir, pszInfile, (int)(p - pszInfile + 1)); // I3481
|
||||
kmcmp::CompileDir[(int)(p - pszInfile + 1)] = 0;
|
||||
|
|
@ -104,7 +196,7 @@ bool CompileKeyboard(char* pszInfile,
|
|||
kmcmp::CompileDir[0] = 0;
|
||||
|
||||
msgproc = pMsgproc;
|
||||
msgprocContext = AmsgprocContext;
|
||||
msgprocContext = (void*)AmsgprocContext;
|
||||
kmcmp::currentLine = 0;
|
||||
kmcmp::nErrors = 0;
|
||||
|
||||
|
|
@ -231,7 +323,8 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk)
|
|||
fk->dpDeadKeyArray = NULL;
|
||||
fk->cxVKDictionary = 0; // I3438
|
||||
fk->dpVKDictionary = NULL; // I3438
|
||||
|
||||
fk->extra = new FILE_KEYBOARD_EXTRA;
|
||||
fk->extra->kvksFilename = u"";
|
||||
/* fk->szMessage[0] = 0;
|
||||
fk->szLanguageName[0] = 0;*/
|
||||
fk->dwBitmapSize = 0;
|
||||
|
|
@ -251,12 +344,8 @@ bool CompileKeyboardHandle(FILE* fp_in, PFILE_KEYBOARD fk)
|
|||
}
|
||||
|
||||
/* Add a system store for the Keyman edition number */
|
||||
u16sprintf(str, LINESIZE, L"%d", 0); // I3481
|
||||
AddStore(fk, TSS_CUSTOMKEYMANEDITION, str);
|
||||
|
||||
PKMX_WCHAR tbuf = strtowstr((KMX_CHAR*) "Keyman");
|
||||
AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, tbuf);
|
||||
delete tbuf;
|
||||
AddStore(fk, TSS_CUSTOMKEYMANEDITION, u"0");
|
||||
AddStore(fk, TSS_CUSTOMKEYMANEDITIONNAME, u"Keyman");
|
||||
|
||||
// must preprocess for group and store names -> this isn't really necessary, but never mind!
|
||||
while ((msg = ReadLine(fp_in, str, TRUE)) == CERR_None)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "kmcompx.h"
|
||||
#include <kmx_file.h>
|
||||
#include <string>
|
||||
|
||||
#define LINESIZE 8192
|
||||
#define GLOBAL_BUFSIZE 4096
|
||||
|
|
@ -71,85 +72,93 @@
|
|||
enum FileStoreType { FST_STORE, FST_OPTION, FST_RESERVED };
|
||||
|
||||
struct FILE_STORE {
|
||||
KMX_DWORD dwSystemID;
|
||||
KMX_WCHAR szName[SZMAX_STORENAME]; // the name of the store
|
||||
PKMX_WCHAR dpString; // from start of store structure
|
||||
//FileStoreType fstType;
|
||||
KMX_BOOL fIsStore;
|
||||
KMX_BOOL fIsReserved;
|
||||
KMX_BOOL fIsOption;
|
||||
KMX_BOOL fIsDebug;
|
||||
KMX_BOOL fIsCall;
|
||||
int line;
|
||||
};
|
||||
|
||||
typedef FILE_STORE * PFILE_STORE;
|
||||
KMX_DWORD dwSystemID;
|
||||
KMX_WCHAR szName[SZMAX_STORENAME]; // the name of the store
|
||||
PKMX_WCHAR dpString; // from start of store structure
|
||||
//FileStoreType fstType;
|
||||
KMX_BOOL fIsStore;
|
||||
KMX_BOOL fIsReserved;
|
||||
KMX_BOOL fIsOption;
|
||||
KMX_BOOL fIsDebug;
|
||||
KMX_BOOL fIsCall;
|
||||
int line;
|
||||
};
|
||||
|
||||
typedef FILE_STORE *PFILE_STORE;
|
||||
|
||||
struct FILE_KEY {
|
||||
KMX_WCHAR Key; // WCHAR for consistency; only a byte used however
|
||||
KMX_WORD LineStoreIndex;
|
||||
KMX_DWORD Line;
|
||||
KMX_DWORD ShiftFlags;
|
||||
PKMX_WCHAR dpOutput; // from start of key structure
|
||||
PKMX_WCHAR dpContext; // from start of key structure
|
||||
};
|
||||
KMX_WCHAR Key; // WCHAR for consistency; only a byte used however
|
||||
KMX_WORD LineStoreIndex;
|
||||
KMX_DWORD Line;
|
||||
KMX_DWORD ShiftFlags;
|
||||
PKMX_WCHAR dpOutput; // from start of key structure
|
||||
PKMX_WCHAR dpContext; // from start of key structure
|
||||
};
|
||||
typedef FILE_KEY *PFILE_KEY;
|
||||
|
||||
|
||||
struct FILE_GROUP {
|
||||
KMX_WCHAR szName[SZMAX_GROUPNAME];
|
||||
PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure
|
||||
PKMX_WCHAR dpMatch; // from start of group structure
|
||||
PKMX_WCHAR dpNoMatch; // from start of group structure
|
||||
KMX_DWORD cxKeyArray; // in array items
|
||||
KMX_BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
|
||||
KMX_BOOL fReadOnly; // group(xx) [readonly] <-- specified or not
|
||||
KMX_DWORD Line;
|
||||
};
|
||||
KMX_WCHAR szName[SZMAX_GROUPNAME];
|
||||
PFILE_KEY dpKeyArray; // address of first item in key array, from start of group structure
|
||||
PKMX_WCHAR dpMatch; // from start of group structure
|
||||
PKMX_WCHAR dpNoMatch; // from start of group structure
|
||||
KMX_DWORD cxKeyArray; // in array items
|
||||
KMX_BOOL fUsingKeys; // group(xx) [using keys] <-- specified or not
|
||||
KMX_BOOL fReadOnly; // group(xx) [readonly] <-- specified or not
|
||||
KMX_DWORD Line;
|
||||
};
|
||||
typedef FILE_GROUP *PFILE_GROUP;
|
||||
|
||||
struct FILE_DEADKEY
|
||||
{
|
||||
KMX_WCHAR szName[SZMAX_DEADKEYNAME];
|
||||
struct FILE_DEADKEY {
|
||||
KMX_WCHAR szName[SZMAX_DEADKEYNAME];
|
||||
};
|
||||
|
||||
typedef FILE_DEADKEY *PFILE_DEADKEY;
|
||||
|
||||
struct FILE_VKDICTIONARY
|
||||
{
|
||||
KMX_WCHAR szName[SZMAX_VKDICTIONARYNAME];
|
||||
struct FILE_VKDICTIONARY {
|
||||
KMX_WCHAR szName[SZMAX_VKDICTIONARYNAME];
|
||||
};
|
||||
typedef FILE_VKDICTIONARY *PFILE_VKDICTIONARY;
|
||||
|
||||
/**
|
||||
* Extra metadata for API consumers
|
||||
*/
|
||||
struct FILE_KEYBOARD_EXTRA {
|
||||
std::u16string kvksFilename; // original TSS_VISUALKEYBOARD value
|
||||
};
|
||||
|
||||
typedef struct FILE_KEYBOARD_EXTRA* PFILE_KEYBOARD_EXTRA;
|
||||
|
||||
struct FILE_KEYBOARD {
|
||||
KMX_DWORD KeyboardID; // as stored in HKEY_LOCAL_MACHINE//system//currentcontrolset//control//keyboard layouts
|
||||
KMX_DWORD KeyboardID; // deprecated, unused
|
||||
|
||||
KMX_DWORD version; // keyboard file version with VERSION keyword
|
||||
KMX_DWORD version; // keyboard file version with VERSION keyword
|
||||
|
||||
PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure
|
||||
PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure
|
||||
PFILE_STORE dpStoreArray; // address of first item in store array, from start of store structure
|
||||
PFILE_GROUP dpGroupArray; // address of first item in group array, from start of group structure
|
||||
|
||||
KMX_DWORD cxStoreArray; // in number of items
|
||||
KMX_DWORD cxGroupArray; // in number of items
|
||||
KMX_DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1]
|
||||
KMX_DWORD cxStoreArray; // in number of items
|
||||
KMX_DWORD cxGroupArray; // in number of items
|
||||
KMX_DWORD StartGroup[2]; // index of starting groups [ANSI=0, Unicode=1]
|
||||
|
||||
KMX_DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)
|
||||
KMX_DWORD dwHotKey; // standard windows hotkey (hiword=shift/ctrl/alt stuff, loword=vkey)
|
||||
|
||||
KMX_WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name
|
||||
KMX_WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name
|
||||
KMX_WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information
|
||||
KMX_WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard
|
||||
PKMX_BYTE lpBitmap;
|
||||
KMX_DWORD dwBitmapSize;
|
||||
KMX_DWORD dwFlags; // Flags for the keyboard file
|
||||
KMX_WCHAR szName[SZMAX_KEYBOARDNAME]; // Keyboard layout name
|
||||
KMX_WCHAR szLanguageName[SZMAX_LANGUAGENAME]; // Language name
|
||||
KMX_WCHAR szCopyright[SZMAX_COPYRIGHT]; // Copyright information
|
||||
KMX_WCHAR szMessage[SZMAX_MESSAGE]; // General information about the keyboard
|
||||
PKMX_BYTE lpBitmap;
|
||||
KMX_DWORD dwBitmapSize;
|
||||
KMX_DWORD dwFlags; // Flags for the keyboard file
|
||||
|
||||
KMX_DWORD currentGroup; // temp - current processing group
|
||||
KMX_DWORD currentStore; // temp - current processing store
|
||||
KMX_DWORD cxDeadKeyArray;
|
||||
PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array
|
||||
KMX_DWORD cxVKDictionary;
|
||||
PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary
|
||||
};
|
||||
KMX_DWORD currentGroup; // temp - current processing group
|
||||
KMX_DWORD currentStore; // temp - current processing store
|
||||
KMX_DWORD cxDeadKeyArray;
|
||||
PFILE_DEADKEY dpDeadKeyArray; // temp - dead key array
|
||||
KMX_DWORD cxVKDictionary;
|
||||
PFILE_VKDICTIONARY dpVKDictionary; // temp - virtual key dictionary
|
||||
|
||||
PFILE_KEYBOARD_EXTRA extra;
|
||||
};
|
||||
|
||||
typedef FILE_KEYBOARD *PFILE_KEYBOARD;
|
||||
|
||||
|
|
@ -167,34 +176,34 @@ const KMX_DWORD sz_FILE_VKDICTIONARY = sizeof(FILE_VKDICTIONARY);
|
|||
const KMX_DWORD sz_FILE_KEYBOARD = sizeof(FILE_KEYBOARD);
|
||||
|
||||
struct COMPMSG {
|
||||
KMX_CHAR szText[SZMAX_ERRORTEXT];
|
||||
KMX_DWORD Line;
|
||||
KMX_DWORD dwMsgCode;
|
||||
};
|
||||
KMX_CHAR szText[SZMAX_ERRORTEXT];
|
||||
KMX_DWORD Line;
|
||||
KMX_DWORD dwMsgCode;
|
||||
};
|
||||
|
||||
typedef COMPMSG *PCOMPMSG;
|
||||
|
||||
struct COMPILEMESSAGES {
|
||||
int nMessages;
|
||||
int nErrors;
|
||||
int nMessages;
|
||||
int nErrors;
|
||||
|
||||
PCOMPMSG cm;
|
||||
PCOMPMSG cm;
|
||||
|
||||
KMX_DWORD fatalCode;
|
||||
KMX_CHAR szFatalText[SZMAX_ERRORTEXT];
|
||||
KMX_DWORD fatalCode;
|
||||
KMX_CHAR szFatalText[SZMAX_ERRORTEXT];
|
||||
|
||||
KMX_DWORD currentLine;
|
||||
};
|
||||
KMX_DWORD currentLine;
|
||||
};
|
||||
|
||||
typedef COMPILEMESSAGES *PCOMPILEMESSAGES;
|
||||
|
||||
/*
|
||||
struct TVersion
|
||||
{
|
||||
//int MinVersion; // 0x0500 usually
|
||||
//int CompilerVersion[4];
|
||||
//int MinCompilerVersion[4];
|
||||
int KeyboardVersion; // 0x0500 usually
|
||||
//int MinVersion; // 0x0500 usually
|
||||
//int CompilerVersion[4];
|
||||
//int MinCompilerVersion[4];
|
||||
int KeyboardVersion; // 0x0500 usually
|
||||
};
|
||||
|
||||
extern TVersion FVersionInfo;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ PKMX_WCHAR strtowstr(PKMX_STR in);
|
|||
PFILE_STORE FindSystemStore(PFILE_KEYBOARD fk, KMX_DWORD dwSystemID);
|
||||
FILE* UTF16TempFromUTF8(FILE* fp_in , KMX_BOOL hasPreamble);
|
||||
KMX_DWORD WriteCompiledKeyboard(PFILE_KEYBOARD fk, KMX_BYTE**data, size_t& dataSize);
|
||||
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, KMX_WCHAR const * str, KMX_DWORD *dwStoreID= NULL);
|
||||
KMX_DWORD AddStore(PFILE_KEYBOARD fk, KMX_DWORD SystemID, const KMX_WCHAR * str, KMX_DWORD *dwStoreID= NULL);
|
||||
KMX_DWORD ReadLine(FILE* fp_in , PKMX_WCHAR wstr, KMX_BOOL PreProcess);
|
||||
KMX_DWORD ParseLine(PFILE_KEYBOARD fk, PKMX_WCHAR str);
|
||||
KMX_DWORD ProcessGroupLine(PFILE_KEYBOARD fk, PKMX_WCHAR p);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ endif
|
|||
name_suffix = []
|
||||
|
||||
if cpp_compiler.get_id() == 'emscripten'
|
||||
links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '-sEXPORTED_RUNTIME_METHODS=[\'cwrap\', \'UTF8ToString\']']
|
||||
links += ['-lnodefs.js', '-sMODULARIZE', '-sEXPORT_ES6', '--whole-archive', '--bind', '-sEXPORTED_RUNTIME_METHODS=[\'cwrap\', \'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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue