feat(developer): provide line number for some kmw compiler messages

Fixes #9931.

Provide additional line and file context for some KeymanWeb
compiler messages. This change requires debug data in the intermediate
kmx data provided to the kmw compiler, which should have no impact on
the final .js if debug=false.

This commit only addresses line number data in
Error_NotSupportedInKeymanWebContext and
Error_NotSupportedInKeymanWebOutput.

There are other compiler messages which could benefit from this data:
  * Warn_OptionStoreNameInvalid
  * Error_VirtualCharacterKeysNotSupportedInKeymanWeb
  * Error_VirtualKeysNotValidForMnemonicLayouts
  * Warn_ExtendedShiftFlagsNotSupportedInKeymanWeb
  * Hint_UnreachableKeyCode
  * Error_NotSupportedInKeymanWebStore
  * Warn_HelpFileMissing
  * Warn_EmbedJsFileMissing
  * Error_NotAnyRequiresVersion14
This commit is contained in:
Marc Durdin 2023-11-05 06:12:42 +07:00
parent 8782d32a59
commit 02e1ea59a2
5 changed files with 65 additions and 12 deletions

View file

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

View file

@ -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 += '';
}
}

View file

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

View file

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

View file

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