diff --git a/developer/src/kmc-kmn/src/compiler/compiler.ts b/developer/src/kmc-kmn/src/compiler/compiler.ts index df20b69852..317cfc757c 100644 --- a/developer/src/kmc-kmn/src/compiler/compiler.ts +++ b/developer/src/kmc-kmn/src/compiler/compiler.ts @@ -298,6 +298,12 @@ export class KmnCompiler implements UnicodeSetParser { if(wasm_result.extra.targets & COMPILETARGETS_JS) { wasm_options.target = 1; // CKF_KEYMANWEB TODO use COMPILETARGETS_JS + + // We always want debug data in the intermediate .kmx, so that error + // messages from KMW compiler can give line numbers in .kmn. This + // should have no impact on the final .js if options.debug is false + wasm_options.saveDebug = true; + wasm_result = Module.kmcmp_compile(infile, wasm_options, wasm_interface); if(!wasm_result.result) { return null; diff --git a/developer/src/kmc-kmn/src/kmw-compiler/javascript-strings.ts b/developer/src/kmc-kmn/src/kmw-compiler/javascript-strings.ts index bafbae2794..b7b9817572 100644 --- a/developer/src/kmc-kmn/src/kmw-compiler/javascript-strings.ts +++ b/developer/src/kmc-kmn/src/kmw-compiler/javascript-strings.ts @@ -490,7 +490,7 @@ function JavaScript_CompositeContextValue(fk: KMX.KEYBOARD, fkp: KMX.KEY, pwsz: `this.s${JavaScript_Name(rec.Any.StoreIndex, rec.Any.Store.dpName)})`; break; default: - callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({code: GetCodeName(rec.Code)})); + callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({line: fkp.Line, code: GetCodeName(rec.Code)})); Result += '/*.*/ 0 '; } } @@ -579,7 +579,7 @@ function JavaScript_FullContextValue(fk: KMX.KEYBOARD, fkp: KMX.KEY, pwsz: strin `o:${rec.Index.Index}}`; // I4611 break; default: - callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({code: GetCodeName(rec.Code)})); + callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({line: fkp.Line, code: GetCodeName(rec.Code)})); Result += '/*.*/ 0 '; } } @@ -677,7 +677,7 @@ export function JavaScript_OutputString(fk: KMX.KEYBOARD, FTabStops: string, fkp // These have no output for a context emit break; default: - callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({code: GetCodeName(recContext.Code)})); + callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebContext({line: fkp.Line, code: GetCodeName(recContext.Code)})); Result += nlt + '/*.*/ '; // I4611 } } @@ -885,7 +885,7 @@ export function JavaScript_OutputString(fk: KMX.KEYBOARD, FTabStops: string, fkp len = -1; break; default: - callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebOutput({code: GetCodeName(rec.Code)})); + callbacks.reportMessage(KmwCompilerMessages.Error_NotSupportedInKeymanWebOutput({line: fkp.Line, code: GetCodeName(rec.Code)})); Result += ''; } } diff --git a/developer/src/kmc-kmn/src/kmw-compiler/kmw-compiler-messages.ts b/developer/src/kmc-kmn/src/kmw-compiler/kmw-compiler-messages.ts index 0c2e5bbdb6..a952125571 100644 --- a/developer/src/kmc-kmn/src/kmw-compiler/kmw-compiler-messages.ts +++ b/developer/src/kmc-kmn/src/kmw-compiler/kmw-compiler-messages.ts @@ -1,5 +1,6 @@ import { KmnCompilerMessages } from "../compiler/kmn-compiler-messages.js"; -import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerMessageSpec as m } from "@keymanapp/common-types"; +import { CompilerErrorNamespace, CompilerErrorSeverity, CompilerEvent, CompilerMessageSpec } from "@keymanapp/common-types"; +import { kmnfile } from "./compiler-globals.js"; const Namespace = CompilerErrorNamespace.KmwCompiler; // const SevInfo = CompilerErrorSeverity.Info | Namespace; @@ -8,6 +9,12 @@ const Namespace = CompilerErrorNamespace.KmwCompiler; const SevError = CompilerErrorSeverity.Error | Namespace; // const SevFatal = CompilerErrorSeverity.Fatal | Namespace; +const m = (code: number, message: string, o?: {e?: any, filename?: string, line?: number}) : CompilerEvent => ({ + ...CompilerMessageSpec(code, message, o?.e), + filename: o?.filename ?? kmnfile, + line: o?.line, +}); + export class KmwCompilerMessages extends KmnCompilerMessages { // Note: for legacy reasons, KMWCompilerMessages extends from // KMNCompilerMessages as they share the same error codes. This can be a @@ -19,44 +26,66 @@ export class KmwCompilerMessages extends KmnCompilerMessages { static Error_InvalidBegin = () => m(this.ERROR_InvalidBegin, `A "begin unicode" statement is required to compile a KeymanWeb keyboard`); + static Error_InvalidTouchLayoutFile = (o:{filename:string}) => m(this.ERROR_InvalidTouchLayoutFile, `Touch layout file ${o.filename} is not valid`); + static Warn_DontMixChiralAndNonChiralModifiers = () => m(this.WARN_DontMixChiralAndNonChiralModifiers, `This keyboard contains Ctrl,Alt and LCtrl,LAlt,RCtrl,RAlt sets of modifiers. Use only one or the other set for web target.`); + static Warn_OptionStoreNameInvalid = (o:{name:string}) => m(this.WARN_OptionStoreNameInvalid, `The option store ${o.name} should be named with characters in the range A-Z, a-z, 0-9 and _ only.`); + static Error_VirtualCharacterKeysNotSupportedInKeymanWeb = () => m(this.ERROR_VirtualCharacterKeysNotSupportedInKeymanWeb, `Virtual character keys not currently supported in KeymanWeb`); + static Error_VirtualKeysNotValidForMnemonicLayouts = () => m(this.ERROR_VirtualKeysNotValidForMnemonicLayouts, `Virtual keys are not valid for mnemonic layouts`); + static Warn_ExtendedShiftFlagsNotSupportedInKeymanWeb = (o:{flags:string}) => m(this.WARN_ExtendedShiftFlagsNotSupportedInKeymanWeb, `Extended shift flags ${o.flags} are not supported in KeymanWeb`); + static Hint_UnreachableKeyCode = (o:{key:string}) => m(this.HINT_UnreachableKeyCode, `The rule will never be matched for key ${o.key} because its key code is never fired.`); + static Error_NotSupportedInKeymanWebStore = (o:{code:string,store:string}) => m(this.ERROR_NotSupportedInKeymanWebStore, - `${o.code} is not currently supported in store '${o.store}' when used by any or index`); - static Error_NotSupportedInKeymanWebContext = (o:{code:String}) => m(this.ERROR_NotSupportedInKeymanWebContext, - `Statement ${o.code} is not currently supported in context`); - static Error_NotSupportedInKeymanWebOutput = (o:{code:string}) => m(this.ERROR_NotSupportedInKeymanWebOutput, - `Statement ${o.code} is not currently supported in output`); + `'${o.code}' is not currently supported in store '${o.store}' when used by any or index for web and touch targets`); + + static Error_NotSupportedInKeymanWebContext = (o:{line:number, code:String}) => m(this.ERROR_NotSupportedInKeymanWebContext, + `Statement '${o.code}' is not currently supported in context for web and touch targets`, o); + + static Error_NotSupportedInKeymanWebOutput = (o:{line:number, code:string}) => m(this.ERROR_NotSupportedInKeymanWebOutput, + `Statement '${o.code}' is not currently supported in output for web and touch targets`, o); + static Warn_HelpFileMissing = (o:{filename: string, e:any}) => m(this.WARN_HelpFileMissing, `File ${o.filename} could not be loaded: ${(o.e??'').toString()}`); + static Warn_EmbedJsFileMissing = (o:{filename: string, e:any}) => m(this.WARN_EmbedJsFileMissing, `File ${o.filename} could not be loaded: ${(o.e??'').toString()}`); + static Warn_TouchLayoutMissingLayer = (o:{keyId:string, platformName:string, layerId:string, nextLayer:string}) => m(this.WARN_TouchLayoutMissingLayer, `Key "${o.keyId}" on platform "${o.platformName}", layer "${o.layerId}", references a missing layer "${o.nextLayer}"`); + static Warn_TouchLayoutUnidentifiedKey = (o:{layerId:string}) => m(this.WARN_TouchLayoutUnidentifiedKey, `A key on layer "${o.layerId}" has no identifier.`); + static Error_TouchLayoutInvalidIdentifier = (o:{keyId:string, platformName: string, layerId:string}) => m(this.ERROR_TouchLayoutInvalidIdentifier, `Key "${o.keyId}" on "${o.platformName}", layer "${o.layerId}" has an invalid identifier.`); + static Warn_TouchLayoutCustomKeyNotDefined = (o:{keyId:string, platformName:string, layerId:string}) => m(this.WARN_TouchLayoutCustomKeyNotDefined, `Key "${o.keyId}" on platform "${o.platformName}", layer "${o.layerId}", is a custom key but has no corresponding rule in the source.`); - static Warn_TouchLayoutSpecialLabelOnNormalKey = (o:{keyId:string, platformName:string, layerId:string, label:string}) => m(this.WARN_TouchLayoutSpecialLabelOnNormalKey, - `Key "${o.keyId}" on platform "${o.platformName}", layer "${o.layerId}" does not have the key type "Special" or "Special (active)" but has the label "${o.label}". This feature is only supported in Keyman 14 or later`); + + static Warn_TouchLayoutSpecialLabelOnNormalKey = (o:{keyId:string, platformName:string, layerId:string, label:string}) => + m(this.WARN_TouchLayoutSpecialLabelOnNormalKey, + `Key "${o.keyId}" on platform "${o.platformName}", layer "${o.layerId}" does not have `+ + `the key type "Special" or "Special (active)" but has the label "${o.label}". This feature is only supported in Keyman 14 or later`); + static Error_InvalidKeyCode = (o:{keyId: string}) => m(this.ERROR_InvalidKeyCode, `Invalid key identifier "${o.keyId}"`); + static Warn_TouchLayoutFontShouldBeSameForAllPlatforms = () => m(this.WARN_TouchLayoutFontShouldBeSameForAllPlatforms, `The touch layout font should be the same for all platforms.`); + static Warn_TouchLayoutMissingRequiredKeys = (o:{layerId:string, platformName:string, missingKeys:string}) => m(this.WARN_TouchLayoutMissingRequiredKeys, `Layer "${o.layerId}" on platform "${o.platformName}" is missing the required key(s) '${o.missingKeys}'.`); diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_not_supported_in_keyman_web_output.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_not_supported_in_keyman_web_output.kmn new file mode 100644 index 0000000000..cd2c34bb64 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_not_supported_in_keyman_web_output.kmn @@ -0,0 +1,11 @@ +c Tests ERROR_NotSupportedInKeymanWebOutput for `return` + +store(&NAME) 'ERROR_NotSupportedInKeymanWebOutput' +store(&VERSION) '9.0' +store(&TARGETS) 'web' + +begin unicode > use(main) + +group(main) using keys + ++ 'a' > return diff --git a/developer/src/kmc-kmn/test/test-messages.ts b/developer/src/kmc-kmn/test/test-messages.ts index 0220c2d037..af07abc2ad 100644 --- a/developer/src/kmc-kmn/test/test-messages.ts +++ b/developer/src/kmc-kmn/test/test-messages.ts @@ -80,4 +80,11 @@ describe('CompilerMessages', function () { assert.equal(callbacks.messages[0].message, "A key on layer \"default\" has no identifier."); }); + // ERROR_NotSupportedInKeymanWebOutput + + it('should generate ERROR_NotSupportedInKeymanWebOutput if a rule has `return` in the output', async function() { + await testForMessage(this, ['invalid-keyboards', 'error_not_supported_in_keyman_web_output.kmn'], KmnCompilerMessages.ERROR_NotSupportedInKeymanWebOutput); + assert.equal(callbacks.messages[0].message, "Statement \"return\" is not currently supported in output"); + }); + });