diff --git a/src/SIL.LCModel/DomainImpl/OverridesLing_MoClasses.cs b/src/SIL.LCModel/DomainImpl/OverridesLing_MoClasses.cs index c27ed825..1d6993d4 100644 --- a/src/SIL.LCModel/DomainImpl/OverridesLing_MoClasses.cs +++ b/src/SIL.LCModel/DomainImpl/OverridesLing_MoClasses.cs @@ -4066,6 +4066,126 @@ public override void PostClone(Dictionary copyMap) clonedProcess.OutputOS.RemoveAt(0); } } + /// + /// Gets all of the feature constraints in this rule. + /// + /// The feature constraints. + [VirtualProperty(CellarPropertyType.ReferenceCollection, "PhFeatureConstraint")] + public IEnumerable FeatureConstraints + { + get + { + return GetFeatureConstraints(); + } + } + + /// + /// Gets all of the feature constraints in this rule. + /// + /// The feature constraints. + public List GetFeatureConstraints() + { + var featureConstrs = new List(); + CollectVars(InputOS, featureConstrs); + var contents = new List(); + foreach (var ruleMapping in OutputOS) + { + switch (ruleMapping.ClassID) + { + case MoCopyFromInputTags.kClassId: + var copyInput = ruleMapping as IMoCopyFromInput; + if (copyInput != null && copyInput.ContentRA != null) + { + contents.Add(copyInput.ContentRA); + } + break; + case MoModifyFromInputTags.kClassId: + var modInput = ruleMapping as IMoModifyFromInput; + if (modInput != null && modInput.ContentRA != null) + { + contents.Add(modInput.ContentRA); + } + break; + } + } + CollectVars(contents, featureConstrs); + return featureConstrs; + } + + /// + /// Collects all of the alpha variables in the specified sequence of contexts. + /// + /// The sequence. + /// The feature constraints. + void CollectVars(IEnumerable seq, List featureConstrs) + { + foreach (var ctxt in seq) + { + if (ctxt.ClassID == PhSequenceContextTags.kClassId) + { + IPhSequenceContext psc = ctxt as IPhSequenceContext; + if (psc == null) + continue; + foreach (var memb in psc.MembersRS) + { + if (memb.ClassID == PhSimpleContextNCTags.kClassId) + { + var ncMemb = memb as IPhSimpleContextNC; + CollectVars(ncMemb, featureConstrs); + } + } + } + else if (ctxt.ClassID == PhSimpleContextNCTags.kClassId) + { + var ncCtxt = ctxt as IPhSimpleContextNC; + CollectVars(ncCtxt, featureConstrs); + } + } + } + /// + /// Collects all of the alpha variables in the specified sequence of contexts. + /// + /// The context. + /// The feature indices. + void CollectVars(IPhPhonContext ctxt, List featureConstrs) + { + if (ctxt == null) + return; + + switch (ctxt.ClassID) + { + case PhSequenceContextTags.kClassId: + var seqCtxt = (IPhSequenceContext)ctxt; + foreach (var cur in seqCtxt.MembersRS) + CollectVars(cur as IPhSimpleContextNC, featureConstrs); + break; + + case PhIterationContextTags.kClassId: + var iterCtxt = (IPhIterationContext)ctxt; + CollectVars(iterCtxt.MemberRA, featureConstrs); + break; + + case PhSimpleContextNCTags.kClassId: + var ncCtxt = (IPhSimpleContextNC)ctxt; + CollectVars(ncCtxt.PlusConstrRS, featureConstrs); + CollectVars(ncCtxt.MinusConstrRS, featureConstrs); + break; + } + } + + /// + /// Collects all of the alpha variables in the specified sequence. + /// + /// The sequence of variables. + /// The feature constraints. + void CollectVars(IEnumerable vars, List featureConstrs) + { + foreach (var var in vars) + { + if (!featureConstrs.Contains(var)) + featureConstrs.Add(var); + } + } } internal partial class MoMorphData diff --git a/src/SIL.LCModel/InterfaceAdditions.cs b/src/SIL.LCModel/InterfaceAdditions.cs index d23a3cc9..0ed470e5 100644 --- a/src/SIL.LCModel/InterfaceAdditions.cs +++ b/src/SIL.LCModel/InterfaceAdditions.cs @@ -2107,6 +2107,24 @@ public partial interface IMoInflAffixSlot : ICloneableCmObject IEnumerable OtherInflectionalAffixLexEntries { get; } } + public partial interface IMoAffixProcess + { + /// + /// Gets all of the feature constraints in this rule. + /// + /// The feature constraints. + IEnumerable FeatureConstraints + { + get; + } + + /// + /// Gets all of the feature constraints in this rule. + /// + /// The feature constraints. + public List GetFeatureConstraints(); + } + public partial interface IFsFeatureSystem { /// diff --git a/tests/SIL.LCModel.Tests/DomainImpl/LingTests.cs b/tests/SIL.LCModel.Tests/DomainImpl/LingTests.cs index 9a257f89..03711dc3 100644 --- a/tests/SIL.LCModel.Tests/DomainImpl/LingTests.cs +++ b/tests/SIL.LCModel.Tests/DomainImpl/LingTests.cs @@ -106,6 +106,46 @@ public void NewMoAffixProcessHasInputAndOutput() Assert.That(affixProcess.OutputOS[0], Is.TypeOf(typeof(MoCopyFromInput))); } + /// + /// Verify that a new MoAffixProcess is properly initialized. This is needed at least for the Affix Process slice + /// to work properly. See FWR-1619. + /// + [Test] + public void MoAffixProcessFeatureConstraints() + { + var phData = Cache.LangProject.PhonologicalDataOA; + var entry = Cache.ServiceLocator.GetInstance().Create(); + var affixProcess = Cache.ServiceLocator.GetInstance().Create(); + entry.LexemeFormOA = affixProcess; + + var ctxtInput = Cache.ServiceLocator.GetInstance().Create(); + affixProcess.InputOS.Add(ctxtInput); + var featConstrInput = Cache.ServiceLocator.GetInstance().Create(); + phData.FeatConstraintsOS.Add(featConstrInput); + ctxtInput.PlusConstrRS.Add(featConstrInput); + + var cfi = Cache.ServiceLocator.GetInstance().Create(); + affixProcess.OutputOS.Add(cfi); + var ctxtCfi = Cache.ServiceLocator.GetInstance().Create(); + phData.ContextsOS.Add(ctxtCfi); + cfi.ContentRA = ctxtCfi; + var featConstrCfi = Cache.ServiceLocator.GetInstance().Create(); + phData.FeatConstraintsOS.Add(featConstrCfi); + ctxtCfi.MinusConstrRS.Add(featConstrCfi); + + var mfi = Cache.ServiceLocator.GetInstance().Create(); + affixProcess.OutputOS.Add(mfi); + var ctxtMfi = Cache.ServiceLocator.GetInstance().Create(); + phData.ContextsOS.Add(ctxtMfi); + mfi.ContentRA = ctxtMfi; + var featConstrMfi = Cache.ServiceLocator.GetInstance().Create(); + phData.FeatConstraintsOS.Add(featConstrMfi); + ctxtMfi.PlusConstrRS.Add(featConstrMfi); + + var featureConstrs = affixProcess.FeatureConstraints; + Assert.That(featureConstrs, Has.Count.EqualTo(3)); + } + /// /// Trivial test that a newly created InflAffixTemplate has the Final property set to true. ///