private RoutePatternParameterPart ParseParameter(string routeParameter)
        {
            // See: #475 - these tests don't pass the 'whole' text.
            var templatePart = RouteParameterParser.ParseRouteParameter(routeParameter);

            return(templatePart);
        }
        private static bool ParseParameter(Context context, List <RoutePatternPart> parts)
        {
            Debug.Assert(context.Current == OpenBrace);
            context.Mark();

            context.MoveNext();

            while (true)
            {
                if (context.Current == OpenBrace)
                {
                    // This is an open brace inside of a parameter, it has to be escaped
                    if (context.MoveNext())
                    {
                        if (context.Current != OpenBrace)
                        {
                            // If we see something like "{p1:regex(^\d{3", we will come here.
                            context.Error = Resources.TemplateRoute_UnescapedBrace;
                            return(false);
                        }
                    }
                    else
                    {
                        // This is a dangling open-brace, which is not allowed
                        // Example: "{p1:regex(^\d{"
                        context.Error = Resources.TemplateRoute_MismatchedParameter;
                        return(false);
                    }
                }
                else if (context.Current == CloseBrace)
                {
                    // When we encounter Closed brace here, it either means end of the parameter or it is a closed
                    // brace in the parameter, in that case it needs to be escaped.
                    // Example: {p1:regex(([}}])\w+}. First pair is escaped one and last marks end of the parameter
                    if (!context.MoveNext())
                    {
                        // This is the end of the string -and we have a valid parameter
                        break;
                    }

                    if (context.Current == CloseBrace)
                    {
                        // This is an 'escaped' brace in a parameter name
                    }
                    else
                    {
                        // This is the end of the parameter
                        break;
                    }
                }

                if (!context.MoveNext())
                {
                    // This is a dangling open-brace, which is not allowed
                    context.Error = Resources.TemplateRoute_MismatchedParameter;
                    return(false);
                }
            }

            var text = context.Capture();

            if (text == "{}")
            {
                context.Error = Resources.FormatTemplateRoute_InvalidParameterName(string.Empty);
                return(false);
            }

            var inside  = text.Substring(1, text.Length - 2);
            var decoded = inside.Replace("}}", "}").Replace("{{", "{");

            // At this point, we need to parse the raw name for inline constraint,
            // default values and optional parameters.
            var templatePart = RouteParameterParser.ParseRouteParameter(decoded);

            // See #475 - this is here because InlineRouteParameterParser can't return errors
            if (decoded.StartsWith("*", StringComparison.Ordinal) && decoded.EndsWith("?", StringComparison.Ordinal))
            {
                context.Error = Resources.TemplateRoute_CatchAllCannotBeOptional;
                return(false);
            }

            if (templatePart.IsOptional && templatePart.Default != null)
            {
                // Cannot be optional and have a default value.
                // The only way to declare an optional parameter is to have a ? at the end,
                // hence we cannot have both default value and optional parameter within the template.
                // A workaround is to add it as a separate entry in the defaults argument.
                context.Error = Resources.TemplateRoute_OptionalCannotHaveDefaultValue;
                return(false);
            }

            var parameterName = templatePart.Name;

            if (IsValidParameterName(context, parameterName))
            {
                parts.Add(templatePart);
                return(true);
            }
            else
            {
                return(false);
            }
        }