From 4b04dfed2ac93a673807f2fa9ca020b1d3ed2815 Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 09:07:10 +0000 Subject: [PATCH] fix(grammar): dedupe merged signal lists Co-Authored-By: Virgil --- grammar.go | 37 +++++++++++++++++++++++++------------ loader_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/grammar.go b/grammar.go index 38a6609..184bf2d 100644 --- a/grammar.go +++ b/grammar.go @@ -122,18 +122,10 @@ func mergeSignalData(dst *SignalData, src SignalData) { if dst == nil { return } - if len(src.NounDeterminers) > 0 { - dst.NounDeterminers = append(dst.NounDeterminers, src.NounDeterminers...) - } - if len(src.VerbAuxiliaries) > 0 { - dst.VerbAuxiliaries = append(dst.VerbAuxiliaries, src.VerbAuxiliaries...) - } - if len(src.VerbInfinitive) > 0 { - dst.VerbInfinitive = append(dst.VerbInfinitive, src.VerbInfinitive...) - } - if len(src.VerbNegation) > 0 { - dst.VerbNegation = append(dst.VerbNegation, src.VerbNegation...) - } + dst.NounDeterminers = appendUniqueStrings(dst.NounDeterminers, src.NounDeterminers...) + dst.VerbAuxiliaries = appendUniqueStrings(dst.VerbAuxiliaries, src.VerbAuxiliaries...) + dst.VerbInfinitive = appendUniqueStrings(dst.VerbInfinitive, src.VerbInfinitive...) + dst.VerbNegation = appendUniqueStrings(dst.VerbNegation, src.VerbNegation...) if len(src.Priors) == 0 { return } @@ -148,6 +140,27 @@ func mergeSignalData(dst *SignalData, src SignalData) { } } +func appendUniqueStrings(dst []string, values ...string) []string { + if len(values) == 0 { + return dst + } + seen := make(map[string]struct{}, len(dst)) + for _, value := range dst { + seen[value] = struct{}{} + } + for _, value := range values { + if value == "" { + continue + } + if _, ok := seen[value]; ok { + continue + } + seen[value] = struct{}{} + dst = append(dst, value) + } + return dst +} + func grammarDataHasContent(data *GrammarData) bool { if data == nil { return false diff --git a/loader_test.go b/loader_test.go index eeb949a..ec20244 100644 --- a/loader_test.go +++ b/loader_test.go @@ -454,6 +454,49 @@ func TestMergeGrammarData(t *testing.T) { } } +func TestMergeGrammarData_DeduplicatesSignals(t *testing.T) { + const lang = "zy" + original := GetGrammarData(lang) + t.Cleanup(func() { + SetGrammarData(lang, original) + }) + + SetGrammarData(lang, &GrammarData{ + Signals: SignalData{ + NounDeterminers: []string{"the", "a"}, + VerbAuxiliaries: []string{"will"}, + VerbInfinitive: []string{"to"}, + VerbNegation: []string{"not"}, + }, + }) + + MergeGrammarData(lang, &GrammarData{ + Signals: SignalData{ + NounDeterminers: []string{"a", "some"}, + VerbAuxiliaries: []string{"will", "can"}, + VerbInfinitive: []string{"to", "de"}, + VerbNegation: []string{"not", "never"}, + }, + }) + + data := GetGrammarData(lang) + if data == nil { + t.Fatal("GetGrammarData returned nil") + } + if got, want := data.Signals.NounDeterminers, []string{"the", "a", "some"}; !slices.Equal(got, want) { + t.Fatalf("NounDeterminers = %v, want %v", got, want) + } + if got, want := data.Signals.VerbAuxiliaries, []string{"will", "can"}; !slices.Equal(got, want) { + t.Fatalf("VerbAuxiliaries = %v, want %v", got, want) + } + if got, want := data.Signals.VerbInfinitive, []string{"to", "de"}; !slices.Equal(got, want) { + t.Fatalf("VerbInfinitive = %v, want %v", got, want) + } + if got, want := data.Signals.VerbNegation, []string{"not", "never"}; !slices.Equal(got, want) { + t.Fatalf("VerbNegation = %v, want %v", got, want) + } +} + func TestGrammarDataLanguageTagNormalisation(t *testing.T) { const rawLang = "tl_PH" const canonicalLang = "tl-PH"