private PatternNode?ReadNode(SeekableStringReader reader, char?stopChar = null) { PatternNode?node = null; int c, len, start; Reset(); void Reset() { len = 0; start = reader.NextPosition; } PatternNode?AppendMatch(string pattern) { if (len > 0) { node += new MatchNode(pattern.Substring(start, len)); } return(node); } while ((c = reader.Read()) > -1) { if (c == stopChar) { return(AppendMatch(pattern)); } PatternNode?next; switch (c) { case Constants.Slash: next = SegmentStartNode.Instance; break; case Constants.Wildcard: next = WildcardNode.Instance; break; case Constants.VariableStart: next = ReadVariableNode(reader); break; case Constants.OptionalStart: next = ReadOptionalNode(reader); break; case Constants.OptionalEnd: errorsSink.AddError($"There is an unexpected '{(char)c}'.", reader.NextPosition - 1); return(null); case Constants.EscapeSequenceStart: if (!ShouldEscape(reader)) { len++; continue; } AppendMatch(pattern); reader.NextPosition += Constants.EscapeSequence.Length; start = reader.NextPosition - 1; len = 1; continue; default: len++; continue; } // failed to parse! if (next is null) { return(null); } if (len > 0) { node += new MatchNode(pattern.Substring(start, len)); } node += next; Reset(); } // expected an end char but didn't find it if (stopChar.HasValue) { errorsSink.AddError($"There is a missing '{stopChar}'."); return(null); } node += len == 0 ? MatchNode.Empty : new MatchNode(pattern.Substring(reader.NextPosition - len, len)); return(node); }
internal PatternNode?Parse() { using (var reader = new SeekableStringReader(pattern)) return(ReadNode(reader)); }