diff --git a/src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/AnalysisRewriteRule.cs b/src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/AnalysisRewriteRule.cs index d680e23ea..1915e5ccd 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/AnalysisRewriteRule.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/AnalysisRewriteRule.cs @@ -81,6 +81,13 @@ Constraint constraint in sr.Rhs.Children.Cast< if (_rule.ApplicationMode == RewriteApplicationMode.Simultaneous) reapplyType = ReapplyType.SelfOpaquing; } + else + { + // NarrowAnalysisRewriteRuleSpec works for expansion, too. + ruleSpec = new NarrowAnalysisRewriteRuleSpec(settings, _rule.Lhs, sr); + mode = RewriteApplicationMode.Simultaneous; + reapplyType = ReapplyType.Deletion; + } Debug.Assert(ruleSpec != null); PhonologicalPatternRule patternRule = null; diff --git a/src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/NarrowAnalysisRewriteRuleSpec.cs b/src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/NarrowAnalysisRewriteRuleSpec.cs index 820842c91..469f3020a 100644 --- a/src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/NarrowAnalysisRewriteRuleSpec.cs +++ b/src/SIL.Machine.Morphology.HermitCrab/PhonologicalRules/NarrowAnalysisRewriteRuleSpec.cs @@ -51,6 +51,7 @@ Constraint constraint in _analysisRhs.Children.Cast subrules new EpenthesisSynthesisRewriteSubruleSpec(matcherSettings, isIterative, subrule, i) ); } + else + { + // NarrowSynthesisRewriteSubruleSpec works for expansion, too. + SubruleSpecs.Add( + new NarrowSynthesisRewriteSubruleSpec( + matcherSettings, + isIterative, + lhs.Children.Count, + subrule, + i + ) + ); + } i++; } } diff --git a/tests/SIL.Machine.Morphology.HermitCrab.Tests/PhonologicalRules/RewriteRuleTests.cs b/tests/SIL.Machine.Morphology.HermitCrab.Tests/PhonologicalRules/RewriteRuleTests.cs index f57de738a..e79cc0d3a 100644 --- a/tests/SIL.Machine.Morphology.HermitCrab.Tests/PhonologicalRules/RewriteRuleTests.cs +++ b/tests/SIL.Machine.Morphology.HermitCrab.Tests/PhonologicalRules/RewriteRuleTests.cs @@ -425,6 +425,170 @@ public void MultipleSegmentRules() AssertMorphsEqual(morpher.ParseWord("buuubuuu"), "27"); } + [Test] + public void MultipleDeletionRules() + { + var highVowel = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons-") + .Symbol("voc+") + .Symbol("high+") + .Value; + var backRndVowel = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons-") + .Symbol("voc+") + .Symbol("back+") + .Symbol("round+") + .Value; + + var rule1 = new RewriteRule + { + Name = "rule1", + Lhs = Pattern.New().Annotation(highVowel).Annotation(highVowel).Value + }; + Allophonic.PhonologicalRules.Add(rule1); + rule1.Subrules.Add( + new RewriteSubrule { LeftEnvironment = Pattern.New().Annotation(backRndVowel).Value } + ); + + var morpher = new Morpher(TraceManager, Language); + AssertMorphsEqual(morpher.ParseWord("bubu"), "27", "19"); + } + + [Test] + public void MergeRules() + { + var highVowel = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons-") + .Symbol("voc+") + .Symbol("high+") + .Value; + var backRndVowel = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons-") + .Symbol("voc+") + .Symbol("back+") + .Symbol("round+") + .Value; + var t = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons+") + .Symbol("alveolar") + .Symbol("del_rel-") + .Symbol("asp-") + .Symbol("vd-") + .Symbol("strident-") + .Value; + + var rule1 = new RewriteRule + { + Name = "rule1", + Lhs = Pattern.New().Annotation(highVowel).Annotation(highVowel).Value + }; + Allophonic.PhonologicalRules.Add(rule1); + rule1.Subrules.Add( + new RewriteSubrule + { + Rhs = Pattern.New().Annotation(t).Value, + LeftEnvironment = Pattern.New().Annotation(backRndVowel).Value + } + ); + + var morpher = new Morpher(TraceManager, Language); + AssertMorphsEqual(morpher.ParseWord("butbut"), "27"); + } + + [Test] + public void MultipleMergeRules() + { + var highVowel = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons-") + .Symbol("voc+") + .Symbol("high+") + .Value; + var backRndVowel = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons-") + .Symbol("voc+") + .Symbol("back+") + .Symbol("round+") + .Value; + var t = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons+") + .Symbol("alveolar") + .Symbol("del_rel-") + .Symbol("asp-") + .Symbol("vd-") + .Symbol("strident-") + .Value; + + var rule1 = new RewriteRule + { + Name = "rule1", + Lhs = Pattern + .New() + .Annotation(backRndVowel) + .Annotation(highVowel) + .Annotation(highVowel) + .Value + }; + Allophonic.PhonologicalRules.Add(rule1); + rule1.Subrules.Add( + new RewriteSubrule { Rhs = Pattern.New().Annotation(t).Annotation(t).Value } + ); + + var morpher = new Morpher(TraceManager, Language); + AssertMorphsEqual(morpher.ParseWord("bttbtt"), "27"); + } + + [Test] + public void ExpandRules() + { + var highVowel = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons-") + .Symbol("voc+") + .Symbol("high+") + .Value; + var backRndVowel = FeatureStruct + .New(Language.PhonologicalFeatureSystem) + .Symbol(HCFeatureSystem.Segment) + .Symbol("cons-") + .Symbol("voc+") + .Symbol("back+") + .Symbol("round+") + .Value; + + var rule1 = new RewriteRule + { + Name = "rule1", + Lhs = Pattern.New().Annotation(backRndVowel).Value, + }; + Allophonic.PhonologicalRules.Add(rule1); + rule1.Subrules.Add( + new RewriteSubrule + { + Rhs = Pattern.New().Annotation(highVowel).Annotation(highVowel).Value + } + ); + + var morpher = new Morpher(TraceManager, Language); + AssertMorphsEqual(morpher.ParseWord("biiiibiiii"), "27"); + } + [Test] public void BoundaryRules() {