Beispiel #1
0
        /// <summary>
        /// State machine analysis of the provided message line, to minimize processing cost overhead.
        /// </summary>
        /// <param name="line">The message line.</param>
        /// <returns>Returns a tuple indicating if this was a vote line, whether this line indicated
        /// that this post should be ignored, and the encapsulated vote line, if applicable.</returns>
        /// <exception cref="InvalidOperationException">Throws if it gets into an unknown state.</exception>
        internal static (bool isVoteLine, bool flagIgnore, VoteLine voteLine) AnalyzeLine(string line)
        {
            bool     isVoteLine = false;
            bool     flagIgnore = false;
            VoteLine voteLine   = null;

            if (string.IsNullOrEmpty(line))
            {
                return(isVoteLine, flagIgnore, voteLine);
            }

            StringBuilder prefixSB    = new StringBuilder();
            StringBuilder markerSB    = new StringBuilder();
            StringBuilder taskSB      = new StringBuilder();
            StringBuilder contentSB   = new StringBuilder();
            StringBuilder tempContent = new StringBuilder();

            MarkerType markerType  = MarkerType.None;
            int        markerValue = 0;

            int ignoreCharCount = 0;

            Stack <TokenState> state        = new Stack <TokenState>();
            TokenState         currentState = TokenState.None;

            foreach (var ch in line)
            {
                switch (currentState)
                {
                case TokenState.None:
                    if (ch == whitespace)
                    {
                        continue;
                    }
                    else if (ch == openBBCode)
                    {
                        state.Push(currentState);
                        currentState = TokenState.BBCode;
                    }
                    else if (ch == prefixChar)
                    {
                        state.Push(currentState);
                        currentState = TokenState.Prefix;
                        prefixSB.Append(ch);
                    }
                    else if (ch == ignoreChar)
                    {
                        state.Push(currentState);
                        currentState    = TokenState.Ignore;
                        ignoreCharCount = 1;
                    }
                    else if (ch == openBracket)
                    {
                        state.Push(currentState);
                        currentState = TokenState.Marker;
                    }
                    else
                    {
                        goto doneExamining;
                    }
                    break;

                case TokenState.BBCode:
                    if (state.Peek() == TokenState.PostMarker)
                    {
                        tempContent.Append(ch);
                    }
                    if (ch == closeBBCode)
                    {
                        currentState = state.Pop();
                    }
                    break;

                case TokenState.Ignore:
                    if (ch == ignoreChar)
                    {
                        ignoreCharCount++;
                        if (ignoreCharCount == 5)
                        {
                            flagIgnore = true;
                            goto doneExamining;
                        }
                    }
                    else if (ch == openBBCode)
                    {
                        state.Push(currentState);
                        currentState = TokenState.BBCode;
                    }
                    else
                    {
                        goto doneExamining;
                    }
                    break;

                case TokenState.Prefix:
                    if (ch == whitespace)
                    {
                        continue;
                    }
                    else if (ch == prefixChar)
                    {
                        prefixSB.Append(ch);
                    }
                    else if (ch == openBBCode)
                    {
                        state.Push(currentState);
                        currentState = TokenState.BBCode;
                    }
                    else if (ch == openBracket)
                    {
                        currentState = TokenState.Marker;
                    }
                    else
                    {
                        goto doneExamining;
                    }
                    break;

                case TokenState.Marker:
                    if (ch == whitespace)
                    {
                        continue;
                    }
                    else if (ch == openBBCode)
                    {
                        state.Push(currentState);
                        currentState = TokenState.BBCode;
                    }
                    else if (markerChars.Contains(ch))
                    {
                        markerSB.Append(ch);
                    }
                    else if (ch == closeBracket)
                    {
                        (markerType, markerValue) = GetMarkerType(markerSB.ToString());
                        if (markerType != MarkerType.None)
                        {
                            isVoteLine   = true;
                            currentState = TokenState.PostMarker;
                        }
                        else
                        {
                            goto doneExamining;
                        }
                    }
                    else
                    {
                        goto doneExamining;
                    }
                    break;

                case TokenState.PostMarker:
                    if (ch == whitespace)
                    {
                        continue;
                    }
                    else if (ch == openBracket && taskSB.Length == 0)
                    {
                        state.Push(currentState);
                        currentState = TokenState.Task;
                    }
                    else if (ch == openBBCode && taskSB.Length == 0)
                    {
                        state.Push(currentState);
                        currentState = TokenState.BBCode;
                        tempContent.Append(ch);
                    }
                    else
                    {
                        contentSB.Append(tempContent.ToString());
                        contentSB.Append(ch);
                        currentState = TokenState.Content;
                    }
                    break;

                case TokenState.Task:
                    if (ch == closeBracket)
                    {
                        currentState = state.Pop();
                    }
                    else if (ch == openBBCode)
                    {
                        state.Push(currentState);
                        currentState = TokenState.BBCode;
                    }
                    else
                    {
                        taskSB.Append(ch);
                    }
                    break;

                case TokenState.Content:
                    contentSB.Append(ch);
                    break;

                default:
                    throw new InvalidOperationException($"Unknown token state value: {currentState}.");
                }
            }

doneExamining:

            if (isVoteLine)
            {
                voteLine = new VoteLine(prefixSB.ToString(), markerSB.ToString(), taskSB.ToString(), contentSB.ToString(), markerType, markerValue);
            }

            return(isVoteLine, flagIgnore, voteLine);
        }