feat(developer): add hint when index() store is longer than any() store

While it does not cause any problems to have a index() store that is
longer than its corresponding any() store, it often indicates a mistake,
as the trailing characters in the store are ignored. Thus, adding as a
hint (which can be disabled via message suppression) rather than as a
warning or error.

Example code:
    store(abc) 'abc'
    store(defg) 'defg'
    any(abc) + 'x' > index(defg, 1)  c generates HINT_IndexStoreLong

Fixes: #10666
This commit is contained in:
Marc Durdin 2024-07-24 07:35:31 +07:00
parent 1449f13eed
commit 09a1ad7b69
9 changed files with 86 additions and 12 deletions

View file

@ -49,13 +49,13 @@
#define CERR_None 0x00000000
#define CERR_EndOfFile 0x00000001
#define CERR_BadCallParams 0x00008002
#define CERR_CannotAllocateMemory 0x00008004
#define CERR_BadCallParams 0x00008002 // TODO: rename to CFATAL_
#define CERR_CannotAllocateMemory 0x00008004 // TODO: rename to CFATAL_
#define CERR_InfileNotExist 0x00004005 // #10678: reduced from fatal to error in 17.0
// #define CERR_CannotCreateOutfile 0x00004006 // #10678: reduced from fatal to error in 17.0, but unused
#define CERR_UnableToWriteFully 0x00008007
#define CERR_UnableToWriteFully 0x00008007 // TODO: rename to CFATAL_
#define CERR_CannotReadInfile 0x00004008 // #10678: reduced from fatal to error in 17.0
#define CERR_SomewhereIGotItWrong 0x00008009
#define CERR_SomewhereIGotItWrong 0x00008009 // TODO: rename to CFATAL_
#define CERR_InvalidToken 0x0000400A
#define CERR_InvalidBegin 0x0000400B
@ -129,7 +129,7 @@
#define CERR_InvalidEthnologueCode 0x0000404D
#define CERR_CannotCreateTempfile 0x0000804E
#define CERR_CannotCreateTempfile 0x0000804E // TODO: rename to CFATAL_
#define CERR_90FeatureOnly_IfSystemStores 0x0000404F
#define CERR_IfSystemStore_NotFound 0x00004050
@ -252,7 +252,9 @@
#define CWARN_VirtualKeyInOutput 0x000020AF
#define CERR_BufferOverflow 0x000080C0
#define CERR_Break 0x000080C1
#define CHINT_IndexStoreLong 0x000010B0
#define CERR_BufferOverflow 0x000080C0 // TODO: Rename to CFATAL_...
#define CERR_Break 0x000080C1 // TODO: Rename to CFATAL_...
#endif // _kmn_compiler_errors_h

View file

@ -735,11 +735,17 @@ export class KmnCompilerMessages {
static WARN_VirtualKeyInOutput = SevWarn | 0x0AF;
static Warn_VirtualKeyInOutput = () => m(this.WARN_VirtualKeyInOutput, `Virtual keys are not supported in output`);
static HINT_IndexStoreLong = SevHint | 0x0B0;
static Hint_IndexStoreLong = () => m(
this.HINT_IndexStoreLong,
`The store referenced in index() is longer than the store referenced in any()`
);
static FATAL_BufferOverflow = SevFatal | 0x0C0;
static Fatal_BufferOverflow = () => m(this.FATAL_BufferOverflow, `The compiler memory buffer overflowed`);
static Fatal_BufferOverflow = () => m(this.FATAL_BufferOverflow, `The compiler memory buffer overflowed`);
static FATAL_Break = SevFatal | 0x0C1;
static Fatal_Break = () => m(this.FATAL_Break, `Compiler interrupted by user`);
static Fatal_Break = () => m(this.FATAL_Break, `Compiler interrupted by user`);
};
/**

View file

@ -0,0 +1,11 @@
store(&NAME) 'warn_index_store_short'
store(&VERSION) '10.0'
begin unicode > use(main)
group(main) using keys
store(abc) 'abc'
store(defg) 'defg'
any(abc) + 'x' > index(defg, 1)

View file

@ -0,0 +1,11 @@
store(&NAME) 'warn_index_store_short_key'
store(&VERSION) '10.0'
begin unicode > use(main)
group(main) using keys
store(abc) 'abc'
store(defg) 'defg'
+ any(abc) > index(defg, 1)

View file

@ -0,0 +1,11 @@
store(&NAME) 'warn_index_store_short'
store(&VERSION) '10.0'
begin unicode > use(main)
group(main) using keys
store(abc) 'abc'
store(defg) 'defg'
any(defg) + 'x' > index(abc, 1)

View file

@ -0,0 +1,11 @@
store(&NAME) 'warn_index_store_short_key'
store(&VERSION) '10.0'
begin unicode > use(main)
group(main) using keys
store(abc) 'abc'
store(defg) 'defg'
+ any(defg) > index(abc, 1)

View file

@ -33,7 +33,7 @@ describe('KmnCompilerMessages', function () {
if(messageId) {
assert.isTrue(callbacks.hasMessage(messageId), `messageId ${messageId.toString(16)} not generated, instead got: `+JSON.stringify(callbacks.messages,null,2));
assert.lengthOf(callbacks.messages, 1);
assert.lengthOf(callbacks.messages, 1, `messages should have 1 entry, instead has: `+JSON.stringify(callbacks.messages,null,2));
} else {
assert.lengthOf(callbacks.messages, 0, `messages should be empty, but instead got: `+JSON.stringify(callbacks.messages,null,2));
}
@ -112,4 +112,20 @@ describe('KmnCompilerMessages', function () {
await testForMessage(this, ['invalid-keyboards', 'error_character_range_too_long.kmn'], KmnCompilerMessages.ERROR_CharacterRangeTooLong);
});
// WARN_IndexStoreShort
it('should generate WARN_IndexStoreShort if a store referenced in index() is shorter than the corresponding any() store', async function() {
await testForMessage(this, ['keyboards', 'warn_index_store_short.kmn'], KmnCompilerMessages.WARN_IndexStoreShort);
callbacks.clear();
await testForMessage(this, ['keyboards', 'warn_index_store_short_key.kmn'], KmnCompilerMessages.WARN_IndexStoreShort);
});
// HINT_IndexStoreLong
it('should generate HINT_IndexStoreLong if a store referenced in index() is longer than the corresponding any() store', async function() {
await testForMessage(this, ['keyboards', 'hint_index_store_long.kmn'], KmnCompilerMessages.HINT_IndexStoreLong);
callbacks.clear();
await testForMessage(this, ['keyboards', 'hint_index_store_long_key.kmn'], KmnCompilerMessages.HINT_IndexStoreLong);
});
});

View file

@ -115,6 +115,7 @@ std::map<KMX_DWORD, const KMX_CHAR*> CompilerErrorMap = {
{ CHINT_UnreachableRule , "This rule will never be matched as another rule takes precedence"},
{ CHINT_NonUnicodeFile , "Keyman Developer has detected that the file has ANSI encoding. Consider converting this file to UTF-8"},
{ CHINT_IndexStoreLong , "The store referenced in index() is longer than the store referenced in any()"},
{ CWARN_TooManyWarnings , "Too many warnings or errors"},
{ CWARN_OldVersion , "The keyboard file is an old version"},

View file

@ -1300,8 +1300,13 @@ KMX_DWORD CheckStatementOffsets(PFILE_KEYBOARD fk, PFILE_GROUP gp, PKMX_WCHAR co
int anyStore = *(q + 2) - 1;
if (xstrlen(fk->dpStoreArray[indexStore].dpString) < xstrlen(fk->dpStoreArray[anyStore].dpString)) {
AddWarning(CWARN_IndexStoreShort); //TODO: if this fails, then we return FALSE instead of an error
const int anyLength = xstrlen(fk->dpStoreArray[anyStore].dpString);
const int indexLength = xstrlen(fk->dpStoreArray[indexStore].dpString);
if (indexLength < anyLength) {
AddWarning(CWARN_IndexStoreShort);
} else if(indexLength > anyLength) {
AddWarning(CHINT_IndexStoreLong);
}
} else if (*(p + 1) == CODE_CONTEXTEX) {
int contextOffset = *(p + 2);