-
-
Notifications
You must be signed in to change notification settings - Fork 43
LT-22607 TonePars use XAmpleParser code for result processing #1002
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,13 +56,15 @@ public class ToneParsInvoker | |
|
|
||
| public const string kTPLexicon = "TPlex.txt"; | ||
| public FLExDBExtractor Extractor { get; set; } | ||
| protected XAmpleParser XAmpleParser { get; set; } | ||
|
|
||
| public ToneParsInvoker( | ||
| string toneParsRuleFile, | ||
| string intxCtlFile, | ||
| string inputFile, | ||
| char decomp, | ||
| LcmCache cache | ||
| LcmCache cache, | ||
| XAmpleParser xAmpleParser | ||
| ) | ||
| { | ||
| ToneParsRuleFile = toneParsRuleFile; | ||
|
|
@@ -73,6 +75,11 @@ LcmCache cache | |
| DatabaseName = ConvertNameToUseAnsiCharacters(cache.ProjectId.Name); | ||
| InitFileNames(); | ||
| Queue = new IdleQueue { IsPaused = true }; | ||
| XAmpleParser = xAmpleParser; | ||
| if ( XAmpleParser == null ) | ||
| { | ||
| XAmpleParser = new XAmpleParser(Cache, null); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Claude - Sonnet 5: This fallback constructs a full Separately: this fallback passes |
||
| } | ||
| } | ||
|
|
||
| private void InitFileNames() | ||
|
|
@@ -684,9 +691,8 @@ public void SaveResultsInDatabase() | |
| IWfiWordform thiswf = GetWordformFromString(wordform); | ||
| if (thiswf != null) | ||
| { | ||
| var parseResult = ConvertParserFilerResultXmlToParseResult( | ||
| ParserFilerXMLString | ||
| ); | ||
| var sb = new StringBuilder(ParserFilerXMLString); | ||
| var parseResult = XAmpleParser.ProcessParseResults(ref sb); | ||
| m_parseFiler.ProcessParse(thiswf, ParserPriority.Low, parseResult); | ||
| } | ||
| i++; | ||
|
|
@@ -724,171 +730,5 @@ protected void ExecuteIdleQueue(IdleQueue idleQueue) | |
| task.Delegate(task.Parameter); | ||
| idleQueue.Clear(); | ||
| } | ||
|
|
||
| //----------------------- | ||
| // ConvertParserFilerResultXmlToParseResult(), TryCreateParseMorph(), and ProcessMsaHvo() are from XAmpleParser.cs | ||
| // (I renamed ParseWord() to ConvertParserFilerResultXmlToParseResult() to avoid confusion.) | ||
| // Ideally, we'd expose them from XAmpleParser.cs | ||
| public ParseResult ConvertParserFilerResultXmlToParseResult(string results) | ||
| { | ||
| //TODO: fix! CheckDisposed(); | ||
| results = results.Replace("DB_REF_HERE", "'0'"); | ||
| results = results.Replace("<...>", "[...]"); | ||
| var wordformElem = XElement.Parse(results.ToString()); | ||
| string errorMessage = null; | ||
| var exceptionElem = wordformElem.Element("Exception"); | ||
| if (exceptionElem != null) | ||
| { | ||
| var totalAnalysesValue = (string)exceptionElem.Attribute("totalAnalyses"); | ||
| switch ((string)exceptionElem.Attribute("code")) | ||
| { | ||
| case "ReachedMaxAnalyses": | ||
| errorMessage = String.Format( | ||
| "Maximum permitted analyses ({0}) reached." /*ParserCoreStrings.ksReachedMaxAnalysesAllowed*/ | ||
| , | ||
| totalAnalysesValue | ||
| ); | ||
| break; | ||
| case "ReachedMaxBufferSize": | ||
| errorMessage = String.Format( | ||
| "Maximum internal buffer size ({0}) reached." /*ParserCoreStrings.ksReachedMaxInternalBufferSize*/ | ||
| , | ||
| totalAnalysesValue | ||
| ); | ||
| break; | ||
| } | ||
| } | ||
| else | ||
| { | ||
| errorMessage = (string)wordformElem.Element("Error"); | ||
| } | ||
|
|
||
| ParseResult result; | ||
| using ( | ||
| new WorkerThreadReadHelper( | ||
| Cache.ServiceLocator.GetInstance<IWorkerThreadReadHandler>() | ||
| ) | ||
| ) | ||
| { | ||
| var analyses = new List<ParseAnalysis>(); | ||
| foreach (XElement analysisElem in wordformElem.Descendants("WfiAnalysis")) | ||
| { | ||
| var morphs = new List<ParseMorph>(); | ||
| bool skip = false; | ||
| foreach (XElement morphElem in analysisElem.Descendants("Morph")) | ||
| { | ||
| ParseMorph morph; | ||
| if (!TryCreateParseMorph(Cache, morphElem, out morph)) | ||
| { | ||
| skip = true; | ||
| break; | ||
| } | ||
| if (morph != null) | ||
| morphs.Add(morph); | ||
| } | ||
|
|
||
| if (!skip && morphs.Count > 0) | ||
| analyses.Add(new ParseAnalysis(morphs)); | ||
| } | ||
| result = new ParseResult(analyses, errorMessage); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| private static bool TryCreateParseMorph( | ||
| LcmCache cache, | ||
| XElement morphElem, | ||
| out ParseMorph morph | ||
| ) | ||
| { | ||
| XElement formElement = morphElem.Element("MoForm"); | ||
| Debug.Assert(formElement != null); | ||
| var formHvo = (string)formElement.Attribute("DbRef"); | ||
|
|
||
| XElement msiElement = morphElem.Element("MSI"); | ||
| Debug.Assert(msiElement != null); | ||
| var msaHvo = (string)msiElement.Attribute("DbRef"); | ||
|
|
||
| // Normally, the hvo for MoForm is a MoForm and the hvo for MSI is an MSA | ||
| // There are four exceptions, though, when an irregularly inflected form is involved: | ||
| // 1. <MoForm DbRef="x"... and x is an hvo for a LexEntryInflType. | ||
| // This is one of the null allomorphs we create when building the | ||
| // input for the parser in order to still get the Word Grammar to have something in any | ||
| // required slots in affix templates. The parser filer can ignore these. | ||
| // 2. <MSI DbRef="y"... and y is an hvo for a LexEntryInflType. | ||
| // This is one of the null allomorphs we create when building the | ||
| // input for the parser in order to still get the Word Grammar to have something in any | ||
| // required slots in affix templates. The parser filer can ignore these. | ||
| // 3. <MSI DbRef="y"... and y is an hvo for a LexEntry. | ||
| // The LexEntry is a variant form for the first set of LexEntryRefs. | ||
| // 4. <MSI DbRef="y"... and y is an hvo for a LexEntry followed by a period and an index digit. | ||
| // The LexEntry is a variant form and the (non-zero) index indicates | ||
| // which set of LexEntryRefs it is for. | ||
| ICmObject objForm; | ||
| if (String.IsNullOrEmpty(formHvo) || | ||
| !cache.ServiceLocator | ||
| .GetInstance<ICmObjectRepository>() | ||
| .TryGetObject(int.Parse(formHvo), out objForm) | ||
| ) | ||
| { | ||
| morph = null; | ||
| return false; | ||
| } | ||
| var form = objForm as IMoForm; | ||
| if (form == null) | ||
| { | ||
| morph = null; | ||
| return true; | ||
| } | ||
|
|
||
| // Irregulary inflected forms can have a combination MSA hvo: the LexEntry hvo, a period, and an index to the LexEntryRef | ||
| Tuple<int, int> msaTuple = ProcessMsaHvo(msaHvo); | ||
| ICmObject objMsa; | ||
| if ( | ||
| !cache.ServiceLocator | ||
| .GetInstance<ICmObjectRepository>() | ||
| .TryGetObject(msaTuple.Item1, out objMsa) | ||
| ) | ||
| { | ||
| morph = null; | ||
| return false; | ||
| } | ||
| var msa = objMsa as IMoMorphSynAnalysis; | ||
| if (msa != null) | ||
| { | ||
| morph = new ParseMorph(form, msa); | ||
| return true; | ||
| } | ||
|
|
||
| var msaAsLexEntry = objMsa as ILexEntry; | ||
| if (msaAsLexEntry != null) | ||
| { | ||
| // is an irregularly inflected form | ||
| // get the MoStemMsa of its variant | ||
| if (msaAsLexEntry.EntryRefsOS.Count > 0) | ||
| { | ||
| ILexEntryRef lexEntryRef = msaAsLexEntry.EntryRefsOS[msaTuple.Item2]; | ||
| ILexSense sense = MorphServices.GetMainOrFirstSenseOfVariant(lexEntryRef); | ||
| var inflType = lexEntryRef.VariantEntryTypesRS[0] as ILexEntryInflType; | ||
| morph = new ParseMorph(form, sense.MorphoSyntaxAnalysisRA, inflType); | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| // if it is anything else, we ignore it | ||
| morph = null; | ||
| return true; | ||
| } | ||
|
|
||
| private static Tuple<int, int> ProcessMsaHvo(string msaHvo) | ||
| { | ||
| string[] msaHvoParts = msaHvo.Split('.'); | ||
| return Tuple.Create( | ||
| int.Parse(msaHvoParts[0]), | ||
| msaHvoParts.Length == 2 ? int.Parse(msaHvoParts[1]) : 0 | ||
| ); | ||
| } | ||
| // ----------------------- | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude - Sonnet 5: The
refonStringBuilder resultsis functionally unnecessary —StringBuilder.Replacemutates in place and returns the same instance, and neither call site (ParseWordhere, orToneParsInvoker.SaveResultsInDatabase) readsresultsafter the call. A plainstring resultsparameter would be simpler and would avoid the caller inToneParsInvoker.cs(SaveResultsInDatabase) having to allocate a throwawayStringBuilderpurely to satisfy this signature.Also: this method doesn't call
CheckDisposed(), unlikeUpdate()/Reset()/ParseWord()/ParseWordXml()on this sameDisposableBase-derived class. Lower severity — this mirrors a pre-existing gap in the code this PR deletes (which had the sameCheckDisposed()omitted, with a//TODO: fix!comment), and there's no demonstrated live path where a disposed instance is called through today — but now that this method is called from another assembly (ToneParsInvoker), it's worth closing for consistency with the rest of the public API.