Beispiel #1
0
        /// <summary>
        /// Совершает обход префиксного дерева токенов с помощью указанного лексера.
        /// </summary>
        /// <param name="lexer">Лексер исходного текста.</param>
        /// <param name="start">Стартовый узел дерева.</param>
        /// <returns>Последний узел и контейнер значений. Если обход закончен неудачно, контейнер значений будет являться <see langword="null"/>.</returns>
        internal static (CommandTreeNode endNode, ValueContainer container) Traverse(ISourceLexer lexer, CommandTreeNode start)
        {
            var currentNode = start;
            var stack       = new Stack <int>();
            var values      = new List <object>();

            var isSequenceRepeat = false;

            while (true)
            {
                var token = lexer.NextSourceToken();
                if (!currentNode.NextNodes.TryGetValue(token, out var reference))
                {
                    break;
                }

                currentNode = reference.Node;

                if (token.Type == TokenType.EndOfText)
                {
                    return(currentNode, new ValueContainer(values.ToArray()));
                }

                if (reference.IsBack)
                {
                    isSequenceRepeat = true;
                }

                var startCount = currentNode.InGroupStartCount;
                if (isSequenceRepeat)
                {
                    if (startCount > 0)
                    {
                        stack.Push(values.Count);
                    }
                }
                else
                {
                    while (startCount > 0)
                    {
                        stack.Push(values.Count);
                        startCount--;
                    }
                }

                if (TokenFacts.IsPlaceholder(currentNode.TokenPrototype.Type))
                {
                    values.Add(token);
                }

                if (currentNode.IsGroupEnd)
                {
                    Debug.Assert(stack.Count > 0);

                    var index             = stack.Pop();
                    var newContainerToken = ReduceToIterationContainer(values, index);

                    if (isSequenceRepeat)
                    {
                        var groupContainerToken = values[^ 1] as TokenWithValue <GroupContainer>;