public void BeAtTheEnd(int[] elements) { // Arrange var cursor = new ElementsCursor <int>(elements, 0); // Assert for (int i = 0; i < elements.Length; i++) { Assert.True(!cursor.IsAtTheEnd()); cursor.MoveNext(); } Assert.True(cursor.IsAtTheEnd()); }
private static void ValidateArgumentEnd(ElementsCursor <char> cursor) { if (cursor.IsAtTheEnd()) { throw new FormatException($"Missing closing bracket at symbol {cursor.Position}."); } }
public MessageTemplate Parse(string messageTemplate) { if (messageTemplate == null) { throw new ArgumentNullException(nameof(messageTemplate)); } if (messageTemplate.Length == 0) { return(new MessageTemplate(Array.Empty <MessageTemplate.Token>())); } var chars = new CharsReadOnlyList(messageTemplate); var cursor = new ElementsCursor <char>(chars, EndOfInput); var tokens = new List <MessageTemplate.Token>(); while (!cursor.IsAtTheEnd()) { switch (cursor.Peek()) { case '{': if (cursor.Peek(1) == '{') { // Escaped opening bracket tokens.Add(ScanTextToken(cursor)); } else { // Argument tokens.Add(ScanArgumentToken(messageTemplate, cursor)); } break; case '}': if (cursor.Peek(1) == '}') { // Escaped closing bracket tokens.Add(ScanTextToken(cursor)); } else { throw new FormatException($"Unescaped closing bracket at symbol {cursor.Position}."); } break; default: tokens.Add(ScanTextToken(cursor)); break; } } return(new MessageTemplate(tokens.ToArray())); }
private MessageTemplate.TextToken ScanTextToken(ElementsCursor <char> cursor) { var text = new StringBuilder(128); while (!cursor.IsAtTheEnd()) { char c = cursor.Peek(); if (c == '{') { if (cursor.Peek(1) == '{') { // Escaped opening bracket text.Append(c); cursor.MoveNext(2); } else { // Beginning of an argument break; } } else if (c == '}') { if (cursor.Peek(1) == '}') { // Escaped closing bracket text.Append(c); cursor.MoveNext(2); } else { // Unescaped closing bracket // Error handled in the top method break; } } else { text.Append(c); cursor.MoveNext(); } } return(new MessageTemplate.TextToken(text.ToString())); }
private SyntaxTrivia ScanWhitespaceTrivia(string input, ElementsCursor <char> cursor) { int start = cursor.Position; while (!cursor.IsAtTheEnd()) { var c = cursor.Peek(); if (!Char.IsWhiteSpace(c)) { break; } cursor.MoveNext(); } if (cursor.Position == start) { return(null); } return(_syntaxFactory.WhitespaceTrivia(input, start, cursor.Position - start)); }
private void ScanLiteralOrIdentifierToken( SyntaxTokenBuilder builder, string input, ElementsCursor <char> cursor) { int start = cursor.Position; char?quote = null; var stringValue = new StringBuilder(128); char first = cursor.Peek(); bool isIdentifier = Char.IsLetter(first); if (first == '"' || first == '\'') { quote = first; isIdentifier = false; cursor.MoveNext(); } while (!cursor.IsAtTheEnd()) { char c = cursor.Peek(); if (Char.IsWhiteSpace(c)) { if (!quote.HasValue) { break; } stringValue.Append(c); cursor.MoveNext(); } else if (c == '=' || c == ':') { if (isIdentifier) { break; } stringValue.Append(c); cursor.MoveNext(); } else if (c == '"' || c == '\'') { // Start of another quoted literal. if (!quote.HasValue) { break; } if (c == quote) { char next = cursor.Peek(1); if (next == c) { // Escaped quote sequence. stringValue.Append(c); cursor.MoveNext(2); } else { // Closing quote symbol. cursor.MoveNext(); break; } } else { // Another quote symbol. stringValue.Append(c); cursor.MoveNext(); } } else { if (isIdentifier && !IsIdentifierSymbol(c)) { isIdentifier = false; } stringValue.Append(c); cursor.MoveNext(); } } // We don't know for sure that this is a pure identifier without a context // but we definitely can identify a pure literal. if (isIdentifier) { _syntaxFactory.IdentifierOrLiteralToken(builder, input, start, cursor.Position - start, stringValue.ToString()); } else { _syntaxFactory.LiteralToken(builder, input, start, cursor.Position - start, stringValue.ToString(), quoted: quote.HasValue); } }
private bool HasMoreTokens(ElementsCursor <SyntaxToken> cursor) { return(!cursor.IsAtTheEnd() && cursor.Peek().Kind != cursor.TerminalElement.Kind); }