Exemplo n.º 1
0
        private static ConstraintParseResults ParseConstraints(
            string text,
            string parameterName,
            int currentIndex,
            int endIndex)
        {
            var constraints = new List <RoutePatternConstraintReference>();
            var state       = ParseState.Start;
            var startIndex  = currentIndex;

            do
            {
                var currentChar = currentIndex > endIndex ? null : (char?)text[currentIndex];
                switch (state)
                {
                case ParseState.Start:
                    switch (currentChar)
                    {
                    case null:
                        state = ParseState.End;
                        break;

                    case ':':
                        state      = ParseState.ParsingName;
                        startIndex = currentIndex + 1;
                        break;

                    case '(':
                        state = ParseState.InsideParenthesis;
                        break;

                    case '=':
                        state = ParseState.End;
                        currentIndex--;
                        break;
                    }
                    break;

                case ParseState.InsideParenthesis:
                    switch (currentChar)
                    {
                    case null:
                        state = ParseState.End;
                        var constraintText = text.Substring(startIndex, currentIndex - startIndex);
                        constraints.Add(RoutePatternFactory.Constraint(constraintText));
                        break;

                    case ')':
                        // Only consume a ')' token if
                        // (a) it is the last token
                        // (b) the next character is the start of the new constraint ':'
                        // (c) the next character is the start of the default value.

                        var nextChar = currentIndex + 1 > endIndex ? null : (char?)text[currentIndex + 1];
                        switch (nextChar)
                        {
                        case null:
                            state          = ParseState.End;
                            constraintText = text.Substring(startIndex, currentIndex - startIndex + 1);
                            constraints.Add(RoutePatternFactory.Constraint(constraintText));
                            break;

                        case ':':
                            state          = ParseState.Start;
                            constraintText = text.Substring(startIndex, currentIndex - startIndex + 1);
                            constraints.Add(RoutePatternFactory.Constraint(constraintText));
                            startIndex = currentIndex + 1;
                            break;

                        case '=':
                            state          = ParseState.End;
                            constraintText = text.Substring(startIndex, currentIndex - startIndex + 1);
                            constraints.Add(RoutePatternFactory.Constraint(constraintText));
                            break;
                        }
                        break;

                    case ':':
                    case '=':
                        // In the original implementation, the Regex would've backtracked if it encountered an
                        // unbalanced opening bracket followed by (not necessarily immediatiely) a delimiter.
                        // Simply verifying that the parantheses will eventually be closed should suffice to
                        // determine if the terminator needs to be consumed as part of the current constraint
                        // specification.
                        var indexOfClosingParantheses = text.IndexOf(')', currentIndex + 1);
                        if (indexOfClosingParantheses == -1)
                        {
                            constraintText = text.Substring(startIndex, currentIndex - startIndex);
                            constraints.Add(RoutePatternFactory.Constraint(constraintText));

                            if (currentChar == ':')
                            {
                                state      = ParseState.ParsingName;
                                startIndex = currentIndex + 1;
                            }
                            else
                            {
                                state = ParseState.End;
                                currentIndex--;
                            }
                        }
                        else
                        {
                            currentIndex = indexOfClosingParantheses;
                        }

                        break;
                    }
                    break;

                case ParseState.ParsingName:
                    switch (currentChar)
                    {
                    case null:
                        state = ParseState.End;
                        var constraintText = text.Substring(startIndex, currentIndex - startIndex);
                        if (constraintText.Length > 0)
                        {
                            constraints.Add(RoutePatternFactory.Constraint(constraintText));
                        }
                        break;

                    case ':':
                        constraintText = text.Substring(startIndex, currentIndex - startIndex);
                        if (constraintText.Length > 0)
                        {
                            constraints.Add(RoutePatternFactory.Constraint(constraintText));
                        }
                        startIndex = currentIndex + 1;
                        break;

                    case '(':
                        state = ParseState.InsideParenthesis;
                        break;

                    case '=':
                        state          = ParseState.End;
                        constraintText = text.Substring(startIndex, currentIndex - startIndex);
                        if (constraintText.Length > 0)
                        {
                            constraints.Add(RoutePatternFactory.Constraint(constraintText));
                        }
                        currentIndex--;
                        break;
                    }
                    break;
                }

                currentIndex++;
            } while (state != ParseState.End);

            return(new ConstraintParseResults(currentIndex, constraints));
        }