/// ------------------------------------------------------------------------------------ /// <summary> /// This function is called after all the quotation related tokens have been processed. /// It generates errors for quotes that are still open at this point. /// </summary> /// <param name="current">The currently open quotes</param> /// ------------------------------------------------------------------------------------ private void CheckForRemaining(OpenQuotes current) { if (current.Level == 0) return; // If the last quotation mark encountered was a closer, and this quotation mark system // collapses adjacent quotes, assume it was multiple quotes collapsed into one if (m_qmCategorizer.CollapseAdjacentQuotes && !current.MostRecent.IsOpener) return; // Print errors starting with inner quotes for (int i = current.Level; i > 1; i--) { if (current.Openers[i - 1] is QToken) ReportError(current.Openers[i - 1] as QToken, string.Format(m_noCloserMsg, i)); } // Prints error for the outermost quote if (m_qmCategorizer.TopLevelClosingExists && current.Openers[0] is QToken) ReportError(current.Openers[0] as QToken, string.Format(m_noCloserMsg, 1)); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Given the information of the currently open quotation marks, process the next encountered /// quotation mark, updating the information and generating errors where appropriate. /// </summary> /// <param name="qmTok">The quotation mark token being processed</param> /// <param name="openQuotes">The currently open quotes</param> /// ------------------------------------------------------------------------------------ private void CheckQuote(QuotationMarkToken qmtok, OpenQuotes openQuotes) { GenerateTraceMsg(qmtok, string.Format(qmtok.IsOpener ? Localize("Level {0} quote opened") : Localize("Level {0} quote closed"), (qmtok.IsOpener ? openQuotes.Level + 1 : openQuotes.Level))); if (m_qmCategorizer.IsMarkForLevel(qmtok.Tts.Text, openQuotes.Level + 1) && qmtok.IsOpener) { // The quote is opened properly openQuotes.Level++; openQuotes.Openers.Add(qmtok); return; } else if (m_qmCategorizer.IsMarkForLevel(qmtok.Tts.Text, openQuotes.Level) && (!qmtok.IsOpener || m_qmCategorizer.OpeningAndClosingAreIdentical(openQuotes.Level))) { // The quote is closed properly openQuotes.Level--; openQuotes.Openers.RemoveAt(openQuotes.Level); return; } int possibleQuoteMarkLevel = m_qmCategorizer.Level(qmtok.Tts.Text, openQuotes.Level, qmtok.IsOpener); if (m_fFoundMissingContinuer) { //Debug.Assert(openQuotes.Level == openQuotes.Openers.Count); Debug.Assert(possibleQuoteMarkLevel != 0); int newLevel = qmtok.IsOpener ? possibleQuoteMarkLevel : possibleQuoteMarkLevel - 1; if (newLevel < openQuotes.Openers.Count) { while (openQuotes.Openers.Count > newLevel) openQuotes.Openers.RemoveAt(openQuotes.Openers.Count - 1); } else if (newLevel > openQuotes.Openers.Count) { while (openQuotes.Openers.Count < newLevel) openQuotes.Openers.Add("Missing Quote"); } openQuotes.Level = newLevel; if (qmtok.IsOpener) openQuotes.Openers.Add(qmtok); else if (openQuotes.Openers.Count > 0 && openQuotes.Openers.Count > openQuotes.Level) openQuotes.Openers.RemoveAt(openQuotes.Level); return; } else if (!m_qmCategorizer.TopLevelClosingExists && possibleQuoteMarkLevel == 1 && openQuotes.Level == 1) { // Opens a top-level quote when top-level closing quotes do not exist openQuotes.Openers.RemoveAt(0); openQuotes.Openers.Add(qmtok); return; } else if (possibleQuoteMarkLevel > openQuotes.Level && !qmtok.IsOpener) { // The quote was closed, but was not opened if (!m_qmCategorizer.CollapseAdjacentQuotes || openQuotes.MostRecent == null) { ReportError(qmtok, string.Format(Localize(m_noOpenerMsg), possibleQuoteMarkLevel)); } return; } else if (possibleQuoteMarkLevel > openQuotes.Level + 1 && qmtok.IsOpener) { // The opener for the quote belongs to a quote level that is too high ReportError(qmtok, string.Format( Localize("Unexpected opening mark: level {0}"), possibleQuoteMarkLevel)); // Add missing tokens for skipped levels while (openQuotes.Openers.Count < possibleQuoteMarkLevel - 1) openQuotes.Openers.Add("Missing Quote"); openQuotes.Level = possibleQuoteMarkLevel; openQuotes.Openers.Add(qmtok); return; } else if (possibleQuoteMarkLevel <= openQuotes.Level && qmtok.IsOpener) { // Opens a quote at the level already open or at too far out a level for (int i = openQuotes.Level; i >= possibleQuoteMarkLevel; i--) { if (!(openQuotes.Openers[i - 1] is QToken)) continue; ReportError(openQuotes.Openers[i - 1] as QToken, string.Format(m_noCloserMsg, i)); } openQuotes.Openers.RemoveRange(possibleQuoteMarkLevel - 1, openQuotes.Level - possibleQuoteMarkLevel + 1); openQuotes.Level = possibleQuoteMarkLevel; openQuotes.Openers.Add(qmtok); return; } // A quote outside the current one is closed before the current one for (int i = possibleQuoteMarkLevel; i < openQuotes.Level; i++) { if (!(openQuotes.Openers[i] is QToken)) continue; ReportError(openQuotes.Openers[i] as QToken, string.Format(m_noCloserMsg, i + 1)); } openQuotes.Openers.RemoveRange(possibleQuoteMarkLevel - 1, openQuotes.Level - possibleQuoteMarkLevel); openQuotes.Level = possibleQuoteMarkLevel - 1; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Goes through the list of quotation related tokens and generates errors for missing /// continuers and quotations. /// </summary> /// ------------------------------------------------------------------------------------ internal void FinalizeResult() { if (m_quotationRelatedTokens.Count == 0) return; OpenQuotes openQuotes = new OpenQuotes(); string prevStyleName = string.Empty; for (int i = 0; i < m_quotationRelatedTokens.Count; i++) { QToken qrtok = m_quotationRelatedTokens[i]; if (qrtok is QuotationMarkToken) { QuotationMarkToken qt = (QuotationMarkToken)qrtok; CheckQuote(qt, openQuotes); openQuotes.MostRecent = qt; m_fFoundMissingContinuer = false; } else if (qrtok is ParaStartToken) { ParaStartToken pstok = qrtok as ParaStartToken; List<string> continuersExpected = GetContinuersNeeded(pstok.StyleName, prevStyleName, openQuotes.Level); prevStyleName = pstok.StyleName; if (continuersExpected.Count > 0) { if (MatchContinuers(i, continuersExpected, openQuotes.Level)) { i += continuersExpected.Count; } else { int contLevel = GetExpectedContinuerLevel( continuersExpected[continuersExpected.Count - 1], openQuotes.Level); ReportError(pstok, string.Format(continuersExpected.Count == 1 ? Localize("Missing continuation mark: level {0}") : Localize("Missing continuation marks: levels 1-{0}"), contLevel)); m_fFoundMissingContinuer = true; } } } } CheckForRemaining(openQuotes); m_quotationRelatedTokens.Clear(); }