From ef212c7e66c2d9d810cfb2dabcebae4ccdaa13bb Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Sat, 3 Oct 2026 11:41:42 +0200 Subject: [PATCH] fix(developer): emit compile error when unsupported statements encountered in stores When a store contains any unsupported statement (any, baselayout, beep, call, context, if, index, layer, notany, nul, platform, reset, save, set, use) or undocumented statement (clearcontext, fix, switch), then emit a compile error. Previously, compiler would not detect use of these statements in stores, which could lead to undefined behaviour at runtime. At time of writing, eight keyboards in the keyboards repository (clavbur9, hausa_ajami_qwerty, sil_cameroon_qwerty, sil_cameroon_azerty, sil_dzongkha, sil_yoruba8, sil_yoruba_bar, sil_yoruba_dot) make use of either beep or nul in stores. Due to compiler unfolding of any/index statements for key part of the rule, these would work in some cases, but this was never supported explicitly nor completely, and so at this point it is better to prevent misuse and add full support as a future task. Fixes: #16718 Test-bot: skip --- .../src/common/include/kmn_compiler_errors.h | 2 ++ .../src/compiler/kmn-compiler-messages.ts | 6 ++++ ...ore_contains_unsupported_statement-any.kmn | 11 ++++++++ ...tains_unsupported_statement-baselayout.kmn | 12 ++++++++ ...re_contains_unsupported_statement-beep.kmn | 9 ++++++ ...re_contains_unsupported_statement-call.kmn | 11 ++++++++ ...ins_unsupported_statement-clearcontext.kmn | 9 ++++++ ...contains_unsupported_statement-context.kmn | 9 ++++++ ...ntains_unsupported_statement-contextex.kmn | 9 ++++++ ...ore_contains_unsupported_statement-fix.kmn | 9 ++++++ ...e_contains_unsupported_statement-ifopt.kmn | 12 ++++++++ ...ns_unsupported_statement-ifsystemstore.kmn | 9 ++++++ ...e_contains_unsupported_statement-index.kmn | 11 ++++++++ ...e_contains_unsupported_statement-layer.kmn | 12 ++++++++ ..._contains_unsupported_statement-notany.kmn | 11 ++++++++ ...ore_contains_unsupported_statement-nul.kmn | 9 ++++++ ...ontains_unsupported_statement-platform.kmn | 12 ++++++++ ...ontains_unsupported_statement-resetopt.kmn | 11 ++++++++ ..._contains_unsupported_statement-return.kmn | 9 ++++++ ...contains_unsupported_statement-saveopt.kmn | 11 ++++++++ ..._contains_unsupported_statement-setopt.kmn | 11 ++++++++ ...s_unsupported_statement-setsystemstore.kmn | 9 ++++++ ..._contains_unsupported_statement-switch.kmn | 9 ++++++ ...ore_contains_unsupported_statement-use.kmn | 9 ++++++ .../test/kmn-compiler-messages.tests.ts | 13 ++++++++- developer/src/kmcmplib/src/Compiler.cpp | 28 +++++++++++++++++++ .../src/kmcmplib/tests/get-test-source.sh | 7 +++-- 27 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-any.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-baselayout.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-beep.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-call.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-clearcontext.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-context.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-contextex.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-fix.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-ifopt.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-ifsystemstore.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-index.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-layer.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-notany.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-nul.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-platform.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-resetopt.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-return.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-saveopt.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-setopt.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-setsystemstore.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-switch.kmn create mode 100644 developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-use.kmn diff --git a/developer/src/common/include/kmn_compiler_errors.h b/developer/src/common/include/kmn_compiler_errors.h index 7b7253d5a2..c319773bee 100644 --- a/developer/src/common/include/kmn_compiler_errors.h +++ b/developer/src/common/include/kmn_compiler_errors.h @@ -289,6 +289,8 @@ namespace KmnCompilerMessages { WARN_DeprecatedValueFormat = SevWarn | 0x0BC, WARN_DeprecatedCompileTarget = SevWarn | 0x0BD, + ERROR_StoreContainsUnsupportedStatement = SevError | 0x0BE, + FATAL_BufferOverflow = SevFatal | 0x0C0 // FATAL_Break = SevFatal | 0x0C1, unused }; diff --git a/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts b/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts index fde5359483..f920985a48 100644 --- a/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts +++ b/developer/src/kmc-kmn/src/compiler/kmn-compiler-messages.ts @@ -930,6 +930,12 @@ export class KmnCompilerMessages { `Compile target '${def(o.p?.[0])}' was deprecated in Keyman 19 and will cause the line to always be ignored by kmc in Keyman 20.`, ); + static ERROR_StoreContainsUnsupportedStatement = SevError | 0x0BE; + static Error_StoreContainsUnsupportedStatement = () => mc( + this.ERROR_StoreContainsUnsupportedStatement, + `A store can contain only characters, deadkeys, virtual keys, and 'outs()' statements.`, + ); + static FATAL_BufferOverflow = SevFatal | 0x0C0; static Fatal_BufferOverflow = () => mc(this.FATAL_BufferOverflow, `The compiler memory buffer overflowed`); diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-any.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-any.kmn new file mode 100644 index 0000000000..2866197f47 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-any.kmn @@ -0,0 +1,11 @@ +store(&NAME) 'error_store_contains_unsupported_statement-any' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(letter) 'F' + +c ERROR_StoreContainsUnsupportedStatement +store(bad-any) any(letter) diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-baselayout.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-baselayout.kmn new file mode 100644 index 0000000000..a636c626d2 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-baselayout.kmn @@ -0,0 +1,12 @@ +store(&NAME) 'error_store_contains_unsupported_statement-baselayout' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(opt) 'opt' + +c ERROR_StoreContainsUnsupportedStatement; note baselayout() compiles to CODE_IFSYSTEMSTORE +store(bad-baselayout) baselayout('us') + diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-beep.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-beep.kmn new file mode 100644 index 0000000000..95af59a891 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-beep.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-beep' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement +store(bad-beep) beep diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-call.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-call.kmn new file mode 100644 index 0000000000..c249d45348 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-call.kmn @@ -0,0 +1,11 @@ +store(&NAME) 'error_store_contains_unsupported_statement-call' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(callee) 'dll.dll:func' + +c ERROR_StoreContainsUnsupportedStatement +store(bad-call) call(callee) diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-clearcontext.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-clearcontext.kmn new file mode 100644 index 0000000000..815365718f --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-clearcontext.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-clearcontext' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement; note clearcontext undocumented, deprecated in v19 +store(bad-clearcontext) clearcontext diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-context.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-context.kmn new file mode 100644 index 0000000000..09ccb08db2 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-context.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-context' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement +store(bad-context) context diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-contextex.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-contextex.kmn new file mode 100644 index 0000000000..88f3e45478 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-contextex.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-contextex' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement +store(bad-contextex) context(1) diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-fix.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-fix.kmn new file mode 100644 index 0000000000..a27fd980f4 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-fix.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-fix' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement; note fix undocumented, deprecated in v19 +store(bad-fix) fix diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-ifopt.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-ifopt.kmn new file mode 100644 index 0000000000..ac886a4518 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-ifopt.kmn @@ -0,0 +1,12 @@ +store(&NAME) 'error_store_contains_unsupported_statement-ifopt' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(opt) 'opt' + +c ERROR_StoreContainsUnsupportedStatement +store(bad-if) if(opt='F') + diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-ifsystemstore.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-ifsystemstore.kmn new file mode 100644 index 0000000000..317397a1d0 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-ifsystemstore.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-ifsystemstore' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement +store(bad-ifs) if(&layer='ah') 'eek' diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-index.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-index.kmn new file mode 100644 index 0000000000..1d219b6612 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-index.kmn @@ -0,0 +1,11 @@ +store(&NAME) 'error_store_contains_unsupported_statement-index' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(letter) 'F' + +c ERROR_StoreContainsUnsupportedStatement +store(bad-index) index(letter, 1) diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-layer.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-layer.kmn new file mode 100644 index 0000000000..f9be3f3965 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-layer.kmn @@ -0,0 +1,12 @@ +store(&NAME) 'error_store_contains_unsupported_statement-layer' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(opt) 'opt' + +c ERROR_StoreContainsUnsupportedStatement; note layer() compiles to CODE_IFSYSTEMSTORE +store(bad-layer) layer('shift') + diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-notany.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-notany.kmn new file mode 100644 index 0000000000..351aa5d42d --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-notany.kmn @@ -0,0 +1,11 @@ +store(&NAME) 'error_store_contains_unsupported_statement-notany' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(letter) 'F' + +c ERROR_StoreContainsUnsupportedStatement +store(bad-notany) notany(letter) diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-nul.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-nul.kmn new file mode 100644 index 0000000000..9d1defacb6 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-nul.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-nul' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement +store(bad-nul) nul diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-platform.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-platform.kmn new file mode 100644 index 0000000000..8a4afa67b1 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-platform.kmn @@ -0,0 +1,12 @@ +store(&NAME) 'error_store_contains_unsupported_statement-platform' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(opt) 'opt' + +c ERROR_StoreContainsUnsupportedStatement; note platform() compiles to CODE_IFSYSTEMSTORE +store(bad-platform) platform('windows') + diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-resetopt.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-resetopt.kmn new file mode 100644 index 0000000000..c9ce42522d --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-resetopt.kmn @@ -0,0 +1,11 @@ +store(&NAME) 'error_store_contains_unsupported_statement-resetopt' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(opt) 'opt' + +c ERROR_StoreContainsUnsupportedStatement +store(bad-reset) reset(opt) diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-return.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-return.kmn new file mode 100644 index 0000000000..0a83a899ac --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-return.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-return' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement +store(bad-reset) return diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-saveopt.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-saveopt.kmn new file mode 100644 index 0000000000..5340e5cf15 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-saveopt.kmn @@ -0,0 +1,11 @@ +store(&NAME) 'error_store_contains_unsupported_statement-saveopt' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(opt) 'opt' + +c ERROR_StoreContainsUnsupportedStatement +store(bad-save) save(opt) diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-setopt.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-setopt.kmn new file mode 100644 index 0000000000..c52cad39ed --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-setopt.kmn @@ -0,0 +1,11 @@ +store(&NAME) 'error_store_contains_unsupported_statement-setopt' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +store(opt) 'opt' + +c ERROR_StoreContainsUnsupportedStatement +store(bad-set) set(opt='X') diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-setsystemstore.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-setsystemstore.kmn new file mode 100644 index 0000000000..30e2cc2217 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-setsystemstore.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-setsystemstore' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement +store(bad-setsystemstore) set(&layer='X') diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-switch.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-switch.kmn new file mode 100644 index 0000000000..208a816d15 --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-switch.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-switch' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement; note switch undocumented and unused, should be eliminated +store(bad-setsystemstore) switch(1) diff --git a/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-use.kmn b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-use.kmn new file mode 100644 index 0000000000..5cb829e0dc --- /dev/null +++ b/developer/src/kmc-kmn/test/fixtures/invalid-keyboards/error_store_contains_unsupported_statement-use.kmn @@ -0,0 +1,9 @@ +store(&NAME) 'error_store_contains_unsupported_statement-use' +store(&VERSION) '9.0' + +begin Unicode > use(main) + +group(main) using keys + +c ERROR_StoreContainsUnsupportedStatement +store(bad-use) use(main) diff --git a/developer/src/kmc-kmn/test/kmn-compiler-messages.tests.ts b/developer/src/kmc-kmn/test/kmn-compiler-messages.tests.ts index 9d924d865b..5b2a9d4c25 100644 --- a/developer/src/kmc-kmn/test/kmn-compiler-messages.tests.ts +++ b/developer/src/kmc-kmn/test/kmn-compiler-messages.tests.ts @@ -412,8 +412,19 @@ describe('KmnCompilerMessages', function () { // WARN_LanguageHeadersDeprecatedInKeyman10 ['ethnologuecode', 'language', 'windowslanguages'].forEach(storeName => - it(`should generate WARN_LanguageHeadersDeprecatedInKeyman10 if the contains deprecated system store "&${storeName}`, async function() { + it(`should generate WARN_LanguageHeadersDeprecatedInKeyman10 if the file contains deprecated system store "&${storeName}"`, async function() { await testForMessage(this, ['keyboards', `warn_language_headers_deprecated_in_keyman10-${storeName}.kmn`], KmnCompilerMessages.WARN_LanguageHeadersDeprecatedInKeyman10); }) ); + + // ERROR_StoreContainsUnsupportedStatement + + ['any', 'index', 'clearcontext', 'fix', 'context', 'nul', 'use', 'return', 'beep', 'switch', + 'call', 'contextex', 'notany', 'setopt', + 'ifopt', 'baselayout', 'layer', 'platform', + 'saveopt', 'resetopt', 'ifsystemstore', 'setsystemstore'].forEach(statement => + it(`should generate ERROR_StoreContainsUnsupportedStatement if a store contains statement "${statement}"`, async function() { + await testForMessage(this, ['invalid-keyboards', `error_store_contains_unsupported_statement-${statement}.kmn`], KmnCompilerMessages.ERROR_StoreContainsUnsupportedStatement); + }) + ); }); diff --git a/developer/src/kmcmplib/src/Compiler.cpp b/developer/src/kmcmplib/src/Compiler.cpp index d90fe86f0a..288cf741c8 100644 --- a/developer/src/kmcmplib/src/Compiler.cpp +++ b/developer/src/kmcmplib/src/Compiler.cpp @@ -139,6 +139,7 @@ KMX_DWORD GetRHS(PFILE_KEYBOARD fk, PKMX_WCHAR p, PKMX_WCHAR buf, int bufsize, i PKMX_WCHAR GetDelimitedString(PKMX_WCHAR *p, KMX_WCHAR const * Delimiters, KMX_WORD Flags); KMX_DWORD GetXString(PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX_WCHAR const * token, PKMX_WCHAR output, int max, int offset, PKMX_WCHAR *newp, int isVKey, int isUnicode); KMX_BOOL GetCompileTargetsFromTargetsStore(KMX_WCHAR *store, int &targets); +KMX_BOOL DoesStoreContainInvalidStatement(PKMX_WCHAR store); int GetGroupNum(PFILE_KEYBOARD fk, PKMX_WCHAR p); @@ -843,6 +844,11 @@ KMX_BOOL ProcessStoreLine(PFILE_KEYBOARD fk, PKMX_WCHAR p) { kmcmp::CodeConstants->reindex(); // has to be done after every character add due to possible use in another store. // I4982 } + if(DoesStoreContainInvalidStatement(sp->dpString)) { + ReportCompilerMessage(KmnCompilerMessages::ERROR_StoreContainsUnsupportedStatement); + return FALSE; + } + fk->cxStoreArray++; // increment now, because GetXString refers to stores if (i > 0) { @@ -1526,6 +1532,28 @@ KMX_DWORD CheckStatementOffsets(PFILE_KEYBOARD fk, PFILE_GROUP gp, PKMX_WCHAR co return STATUS_Success; } +/** + * Stores can contain only characters, deadkeys, and virtual keys (and `outs`). + * Note that `outs()` is expanded during read so there is no `CODE_OUTS`. + * + * @param store + * @return KMX_BOOL + */ +KMX_BOOL DoesStoreContainInvalidStatement(PKMX_WCHAR store) { + for (PKMX_WCHAR p = store; *p; p = incxstr(p)) { + if (*p == UC_SENTINEL) { + auto code = *(p + 1); + if(code == CODE_DEADKEY || code == CODE_EXTENDED) { + continue; + } + + // No other codes are permitted; note, outs() does not have a code as it is expanded at compile time + return TRUE; + } + } + return FALSE; +} + /** * Checks that the order of statements in the context matches the specification. * Rule structure: [context] ['+' key] '>' output diff --git a/developer/src/kmcmplib/tests/get-test-source.sh b/developer/src/kmcmplib/tests/get-test-source.sh index ce88c5ef75..9fcb5fa01d 100755 --- a/developer/src/kmcmplib/tests/get-test-source.sh +++ b/developer/src/kmcmplib/tests/get-test-source.sh @@ -9,7 +9,7 @@ set -eu find "$1" -name '*.kmn' | \ grep -E '(release|experimental)/([a-z0-9_]+)/([a-z0-9_]+)/source/\3\.kmn$' | \ - grep -vE 'masaram_gondi|anii|sil_kmhmu|fv_statimcets|fv_nuucaanul|basic_kbdcherp|basic_kbdolch|sil_yi|gff_geez' + grep -vE 'masaram_gondi|anii|sil_kmhmu|fv_statimcets|fv_nuucaanul|basic_kbdcherp|basic_kbdolch|sil_yi|gff_geez|clavbur9|hausa_ajami_qwerty|sil_cameroon_qwerty|sil_cameroon_azerty|sil_dzongkha|sil_yoruba8|sil_yoruba_bar|sil_yoruba_dot' # #12623: exclude masaram_gondi due to #11806 # #12631: exclude anii, sil_kmhmu as ico references have mismatching case # #12631: exclude fv_statimcets, fv_nuucaanul as these include U+2002 which is not @@ -18,4 +18,7 @@ find "$1" -name '*.kmn' | \ # whitespace, see also issue #12307 # #14746: exclude sil_yi, as this has whitespace in group name 'Unicode Group' # #16717: exclude gff_geez, as this has vkeys referenced in store in an any() -# statement \ No newline at end of file +# statement +# #16718: exclude clavbur9, hausa_ajami_qwerty, sil_cameroon_qwerty, +# sil_cameroon_azerty, sil_dzongkha, sil_yoruba8, sil_yoruba_bar, +# sil_yoruba_dot due to use of `nul` or `beep` in stores