void Parse ()
{
string url = Url;
parameterNames = new Dictionary <string, bool> (StringComparer.OrdinalIgnoreCase);
if (!String.IsNullOrEmpty (url)) {
if (url [0] == '~' || url [0] == '/')
throw new ArgumentException ("Url must not start with '~' or '/'");
if (url.IndexOf ('?') >= 0)
throw new ArgumentException ("Url must not contain '?'");
} else {
segments = new PatternSegment [0];
tokens = new PatternToken [0];
return;
}
string[] parts = url.Split ('/');
int partsCount = segmentCount = parts.Length;
var allTokens = new List <PatternToken> ();
PatternToken tmpToken;
segments = new PatternSegment [partsCount];
for (int i = 0; i < partsCount; i++) {
if (haveSegmentWithCatchAll)
throw new ArgumentException ("A catch-all parameter can only appear as the last segment of the route URL");
int catchAlls = 0;
string part = parts [i];
int partLength = part.Length;
var tokens = new List <PatternToken> ();
if (partLength == 0 && i < partsCount - 1)
throw new ArgumentException ("Consecutive URL segment separators '/' are not allowed");
if (part.IndexOf ("{}") != -1)
throw new ArgumentException ("Empty URL parameter name is not allowed");
if (i > 0)
allTokens.Add (null);
if (part.IndexOfAny (placeholderDelimiters) == -1) {
// no placeholders here, short-circuit it
tmpToken = new PatternToken (PatternTokenType.Literal, part);
tokens.Add (tmpToken);
allTokens.Add (tmpToken);
segments [i].AllLiteral = true;
segments [i].Tokens = tokens;
continue;
}
string tmp;
int from = 0, start;
bool allLiteral = true;
while (from < partLength) {
start = part.IndexOf ('{', from);
if (start >= partLength - 2)
throw new ArgumentException ("Unterminated URL parameter. It must contain matching '}'");
if (start < 0) {
if (part.IndexOf ('}', from) >= from)
throw new ArgumentException ("Unmatched URL parameter closer '}'. A corresponding '{' must precede");
tmp = part.Substring (from);
tmpToken = new PatternToken (PatternTokenType.Literal, tmp);
tokens.Add (tmpToken);
allTokens.Add (tmpToken);
from += tmp.Length;
break;
}
if (from == 0 && start > 0) {
tmpToken = new PatternToken (PatternTokenType.Literal, part.Substring (0, start));
tokens.Add (tmpToken);
allTokens.Add (tmpToken);
}
int end = part.IndexOf ('}', start + 1);
int next = part.IndexOf ('{', start + 1);
if (end < 0 || next >= 0 && next < end)
throw new ArgumentException ("Unterminated URL parameter. It must contain matching '}'");
if (next == end + 1)
throw new ArgumentException ("Two consecutive URL parameters are not allowed. Split into a different segment by '/', or a literal string.");
if (next == -1)
next = partLength;
string token = part.Substring (start + 1, end - start - 1);
PatternTokenType type;
if (token [0] == '*') {
catchAlls++;
haveSegmentWithCatchAll = true;
type = PatternTokenType.CatchAll;
token = token.Substring (1);
} else
type = PatternTokenType.Standard;
if (!parameterNames.ContainsKey (token))
parameterNames.Add (token, true);
tmpToken = new PatternToken (type, token);
tokens.Add (tmpToken);
allTokens.Add (tmpToken);
allLiteral = false;
if (end < partLength - 1) {
token = part.Substring (end + 1, next - end - 1);
tmpToken = new PatternToken (PatternTokenType.Literal, token);
tokens.Add (tmpToken);
allTokens.Add (tmpToken);
end += token.Length;
}
if (catchAlls > 1 || (catchAlls == 1 && tokens.Count > 1))
throw new ArgumentException ("A path segment that contains more than one section, such as a literal section or a parameter, cannot contain a catch-all parameter.");
from = end + 1;
}
segments [i].AllLiteral = allLiteral;
segments [i].Tokens = tokens;
}
if (allTokens.Count > 0)
this.tokens = allTokens.ToArray ();
allTokens = null;
}