diff --git a/Src/LexText/ParserCore/FwXmlTraceManager.cs b/Src/LexText/ParserCore/FwXmlTraceManager.cs
index e71dce1bab..4c8e8d29ec 100644
--- a/Src/LexText/ParserCore/FwXmlTraceManager.cs
+++ b/Src/LexText/ParserCore/FwXmlTraceManager.cs
@@ -69,7 +69,8 @@ public void BeginUnapplyTemplate(AffixTemplate template, Word input)
CreateWordElement("Input", input, true)));
}
- public void EndUnapplyTemplate(AffixTemplate template, Word output, bool unapplied, FailureReason reason)
+ public void EndUnapplyTemplate(AffixTemplate template, Word output, bool unapplied, FailureReason reason,
+ object failureObj)
{
var trace = new XElement(
"TemplateAnalysisTraceOut",
@@ -82,6 +83,11 @@ public void EndUnapplyTemplate(AffixTemplate template, Word output, bool unappli
new XElement("FailureReason", new XAttribute("type", "nonPartialRuleAfterFinalTemplate"))
);
}
+ else if (reason == FailureReason.UnreachableRequiredSlot)
+ {
+ trace.Add(new XElement("FailureReason", new XAttribute("type", "unreachableRequiredSlot"),
+ new XElement("Slot", (failureObj as AffixTemplateSlot)?.Name)));
+ }
((XElement)output.CurrentTrace).Add(trace);
}
diff --git a/Src/LexText/ParserCore/ParserCoreTests/FwXmlTraceManagerTests.cs b/Src/LexText/ParserCore/ParserCoreTests/FwXmlTraceManagerTests.cs
index 1f946b493c..6a5cff77e4 100644
--- a/Src/LexText/ParserCore/ParserCoreTests/FwXmlTraceManagerTests.cs
+++ b/Src/LexText/ParserCore/ParserCoreTests/FwXmlTraceManagerTests.cs
@@ -109,6 +109,21 @@ public void CompoundingFailure_UnknownReasonIsNotGuessedFromOperand()
Assert.That((string)reason.Attribute("type"), Is.EqualTo("unknown"));
}
+ /// Records which required slot made a template fail.
+ [Test]
+ public void TemplateFailure_RecordsUnreachableRequiredSlot()
+ {
+ var template = new AffixTemplate { Name = "synthetic template" };
+ var slot = new AffixTemplateSlot(new AffixProcessRule()) { Name = "synthetic slot" };
+
+ m_manager.EndUnapplyTemplate(template, m_word, false,
+ FailureReason.UnreachableRequiredSlot, slot);
+
+ var reason = m_trace.Element("TemplateAnalysisTraceOut").Element("FailureReason");
+ Assert.That((string)reason.Attribute("type"), Is.EqualTo("unreachableRequiredSlot"));
+ Assert.That(reason.Element("Slot").Value, Is.EqualTo("synthetic slot"));
+ }
+
private RootAllomorph CreateRoot(string headword)
{
var entry = Cache.ServiceLocator.GetInstance().Create(
diff --git a/Src/LexText/ParserCore/ParserCoreTests/HCTraceTransformTests.cs b/Src/LexText/ParserCore/ParserCoreTests/HCTraceTransformTests.cs
index eb71cbb2f1..e46f3f4e9c 100644
--- a/Src/LexText/ParserCore/ParserCoreTests/HCTraceTransformTests.cs
+++ b/Src/LexText/ParserCore/ParserCoreTests/HCTraceTransformTests.cs
@@ -90,6 +90,25 @@ public void CompoundingFailure_UnknownCauseIsExplicit(string type)
Assert.That(Text(Transform(CompoundFailure(type))), Does.Contain("Reason: Unknown reason."));
}
+ /// Names the required slot whose affixes the word cannot supply.
+ [Test]
+ public void TemplateFailure_NamesUnreachableRequiredSlot()
+ {
+ var node = new XElement("MorphologicalRuleAnalysisTrace",
+ new XElement("MorphologicalRule", new XAttribute("type", "affix"), "suffix"),
+ new XElement("Output", "a"),
+ new XElement("TemplateAnalysisTraceOut",
+ new XElement("AffixTemplate", new XAttribute("id", 0), "verb template"),
+ new XElement("Output", "*None*"),
+ new XElement("FailureReason", new XAttribute("type", "unreachableRequiredSlot"),
+ new XElement("Slot", "subject slot"))));
+
+ var text = Text(Transform(node));
+
+ Assert.That(text, Does.Contain("failed."));
+ Assert.That(text, Does.Contain("(Reason: The required slot 'subject slot' cannot be filled"));
+ }
+
private static XElement Allomorph()
{
return new XElement("Allomorph", new XAttribute("id", 42),
diff --git a/Src/Transforms/Presentation/FormatHCTrace.xsl b/Src/Transforms/Presentation/FormatHCTrace.xsl
index 6661e42bd2..da4922e0fc 100644
--- a/Src/Transforms/Presentation/FormatHCTrace.xsl
+++ b/Src/Transforms/Presentation/FormatHCTrace.xsl
@@ -684,6 +684,16 @@ ShowMsaInfo
An affix cannot be applied more than once.
+
+ The required slot '
+
+
+
+
+
+
+ ' cannot be filled: no affix in this slot can be found in what remains of the word, in the order and position the template requires.
+
Unknown reason.
diff --git a/Src/Transforms/Presentation/HCSynthByGlossFormatHCTrace.xsl b/Src/Transforms/Presentation/HCSynthByGlossFormatHCTrace.xsl
index 58e51073a2..b451f4df02 100644
--- a/Src/Transforms/Presentation/HCSynthByGlossFormatHCTrace.xsl
+++ b/Src/Transforms/Presentation/HCSynthByGlossFormatHCTrace.xsl
@@ -828,6 +828,16 @@ ShowMsaInfo
An affix cannot be applied more than once.
+
+ The required slot '
+
+
+
+
+
+
+ ' cannot be filled: no affix in this slot can be found in what remains of the word, in the order and position the template requires.
+
)
diff --git a/Src/Utilities/HCSynthByGloss/HCSynthByGloss/HCSynthByGlossTests/HCSynthByGlossTests.cs b/Src/Utilities/HCSynthByGloss/HCSynthByGloss/HCSynthByGlossTests/HCSynthByGlossTests.cs
index 941646206e..736439a4b4 100644
--- a/Src/Utilities/HCSynthByGloss/HCSynthByGloss/HCSynthByGlossTests/HCSynthByGlossTests.cs
+++ b/Src/Utilities/HCSynthByGloss/HCSynthByGloss/HCSynthByGlossTests/HCSynthByGlossTests.cs
@@ -12,6 +12,7 @@
using SIL.Machine.FeatureModel;
using SIL.Machine.Morphology;
using SIL.Machine.Morphology.HermitCrab;
+using SIL.Machine.Morphology.HermitCrab.MorphologicalRules;
using System.Reflection;
using System.IO;
using HCSynthByGloss;
@@ -145,5 +146,25 @@ public void TraceListsEachFailedEnvironment()
Assert.That(reason.Elements("Environment").Select(e => e.Value).ToList(),
Has.Count.EqualTo(2).And.All.Not.Empty);
}
+
+ /// The trace names the required slot that made a template fail.
+ [Test]
+ public void TraceNamesUnreachableRequiredSlot()
+ {
+ var traceManager = new HcXmlTraceManager { IsTracing = true };
+ var table = new CharacterDefinitionTable();
+ table.AddSegment("a");
+ var trace = new XElement("WordAnalysisTrace");
+ var word = new Word(new Stratum(table), table.Segment("a")) { CurrentTrace = trace };
+ var template = new AffixTemplate { Name = "synthetic template" };
+ var slot = new AffixTemplateSlot(new AffixProcessRule()) { Name = "synthetic slot" };
+
+ traceManager.EndUnapplyTemplate(template, word, false,
+ FailureReason.UnreachableRequiredSlot, slot);
+
+ XElement reason = trace.Element("TemplateAnalysisTraceOut").Element("FailureReason");
+ Assert.That((string)reason.Attribute("type"), Is.EqualTo("unreachableRequiredSlot"));
+ Assert.That(reason.Element("Slot").Value, Is.EqualTo("synthetic slot"));
+ }
}
}
diff --git a/Src/Utilities/HCSynthByGloss/HCSynthByGlossLib/HcXmlTraceManager.cs b/Src/Utilities/HCSynthByGloss/HCSynthByGlossLib/HcXmlTraceManager.cs
index 56a9eee6bb..f442038ffe 100644
--- a/Src/Utilities/HCSynthByGloss/HCSynthByGlossLib/HcXmlTraceManager.cs
+++ b/Src/Utilities/HCSynthByGloss/HCSynthByGlossLib/HcXmlTraceManager.cs
@@ -97,7 +97,13 @@ public void BeginUnapplyTemplate(AffixTemplate template, Word input)
);
}
- public void EndUnapplyTemplate(AffixTemplate template, Word output, bool unapplied, FailureReason reason)
+ public void EndUnapplyTemplate(
+ AffixTemplate template,
+ Word output,
+ bool unapplied,
+ FailureReason reason,
+ object failureObj
+ )
{
var trace = new XElement(
"TemplateAnalysisTraceOut",
@@ -110,6 +116,16 @@ public void EndUnapplyTemplate(AffixTemplate template, Word output, bool unappli
new XElement("FailureReason", new XAttribute("type", "nonPartialRuleAfterFinalTemplate"))
);
}
+ else if (reason == FailureReason.UnreachableRequiredSlot)
+ {
+ trace.Add(
+ new XElement(
+ "FailureReason",
+ new XAttribute("type", "unreachableRequiredSlot"),
+ new XElement("Slot", (failureObj as AffixTemplateSlot)?.Name)
+ )
+ );
+ }
((XElement)output.CurrentTrace).Add(trace);
}