private static UriTemplatePart[] ParseTemplate(string template)
        {
            List <UriTemplatePart> parts = new List <UriTemplatePart>();
            int previousEnd = 0;

            foreach (Match match in ExpressionExpression.Matches(template))
            {
                if (match.Index > previousEnd)
                {
                    parts.Add(new UriTemplatePartLiteral(template.Substring(previousEnd, match.Index - previousEnd)));
                }

                UriTemplatePartType type = UriTemplatePartType.SimpleStringExpansion;
                Group op = match.Groups["Operator"];
                if (op.Success && op.Length > 0)
                {
                    switch (op.Value)
                    {
                    case "+":
                        type = UriTemplatePartType.ReservedStringExpansion;
                        break;

                    case "#":
                        type = UriTemplatePartType.FragmentExpansion;
                        break;

                    case ".":
                        type = UriTemplatePartType.LabelExpansion;
                        break;

                    case "/":
                        type = UriTemplatePartType.PathSegments;
                        break;

                    case ";":
                        type = UriTemplatePartType.PathParameters;
                        break;

                    case "?":
                        type = UriTemplatePartType.Query;
                        break;

                    case "&":
                        type = UriTemplatePartType.QueryContinuation;
                        break;

                    case "=":
                    case ",":
                    case "!":
                    case "@":
                    case "|":
                        throw new NotSupportedException(string.Format("Operator is reserved for future expansion: {0}", op.Value));

                    default:
                        throw new InvalidOperationException("Unreachable");
                    }
                }

                Group variableList = match.Groups["VariableList"];
                VariableReference[] variables;
                if (variableList.Success)
                {
                    string[] specs = variableList.Value.Split(',');
                    variables = new VariableReference[specs.Length];
                    for (int i = 0; i < specs.Length; i++)
                    {
                        variables[i] = VariableReference.Parse(specs[i]);
                    }
                }
                else
                {
                    variables = new VariableReference[0];
                }

                UriTemplatePart part;
                switch (type)
                {
                case UriTemplatePartType.SimpleStringExpansion:
                    part = new UriTemplatePartSimpleExpansion(variables, true);
                    break;

                case UriTemplatePartType.ReservedStringExpansion:
                    part = new UriTemplatePartSimpleExpansion(variables, false);
                    break;

                case UriTemplatePartType.FragmentExpansion:
                    part = new UriTemplatePartFragmentExpansion(variables);
                    break;

                case UriTemplatePartType.LabelExpansion:
                    part = new UriTemplatePartLabelExpansion(variables);
                    break;

                case UriTemplatePartType.PathSegments:
                    part = new UriTemplatePartPathSegmentExpansion(variables);
                    break;

                case UriTemplatePartType.PathParameters:
                    part = new UriTemplatePartPathParametersExpansion(variables);
                    break;

                case UriTemplatePartType.Query:
                    part = new UriTemplatePartQueryExpansion(variables, false);
                    break;

                case UriTemplatePartType.QueryContinuation:
                    part = new UriTemplatePartQueryExpansion(variables, true);
                    break;

                case UriTemplatePartType.Literal:
                default:
                    throw new InvalidOperationException("Unreachable");
                }

                parts.Add(part);
                previousEnd = match.Index + match.Length;
            }

            if (previousEnd < template.Length)
            {
                parts.Add(new UriTemplatePartLiteral(template.Substring(previousEnd)));
            }

            return(parts.ToArray());
        }