-
-
Notifications
You must be signed in to change notification settings - Fork 491
/
TemplateTokenizer.cs
135 lines (113 loc) · 4.01 KB
/
TemplateTokenizer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
using System.Collections.Generic;
using System.Text;
namespace Spectre.Console.Cli
{
internal static class TemplateTokenizer
{
public static IReadOnlyList<TemplateToken> Tokenize(string template)
{
using var buffer = new TextBuffer(template);
var result = new List<TemplateToken>();
while (!buffer.ReachedEnd)
{
EatWhitespace(buffer);
if (!buffer.TryPeek(out var character))
{
break;
}
if (character == '-')
{
result.Add(ReadOption(buffer));
}
else if (character == '|')
{
buffer.Consume('|');
}
else if (character == '<')
{
result.Add(ReadValue(buffer, true));
}
else if (character == '[')
{
result.Add(ReadValue(buffer, false));
}
else
{
throw CommandTemplateException.UnexpectedCharacter(buffer.Original, buffer.Position, character);
}
}
return result;
}
private static void EatWhitespace(TextBuffer buffer)
{
while (!buffer.ReachedEnd)
{
var character = buffer.Peek();
if (!char.IsWhiteSpace(character))
{
break;
}
buffer.Read();
}
}
private static TemplateToken ReadOption(TextBuffer buffer)
{
var position = buffer.Position;
buffer.Consume('-');
if (buffer.IsNext('-'))
{
buffer.Consume('-');
var longValue = ReadOptionName(buffer);
return new TemplateToken(TemplateToken.Kind.LongName, position, longValue, $"--{longValue}");
}
var shortValue = ReadOptionName(buffer);
return new TemplateToken(TemplateToken.Kind.ShortName, position, shortValue, $"-{shortValue}");
}
private static string ReadOptionName(TextBuffer buffer)
{
var builder = new StringBuilder();
while (!buffer.ReachedEnd)
{
var character = buffer.Peek();
if (char.IsWhiteSpace(character) || character == '|')
{
break;
}
builder.Append(buffer.Read());
}
return builder.ToString();
}
private static TemplateToken ReadValue(TextBuffer buffer, bool required)
{
var start = required ? '<' : '[';
var end = required ? '>' : ']';
var position = buffer.Position;
var kind = required ? TemplateToken.Kind.RequiredValue : TemplateToken.Kind.OptionalValue;
// Consume start of value character (< or [).
buffer.Consume(start);
var builder = new StringBuilder();
while (!buffer.ReachedEnd)
{
var character = buffer.Peek();
if (character == end)
{
break;
}
buffer.Read();
builder.Append(character);
}
if (buffer.ReachedEnd)
{
var name = builder.ToString();
var token = new TemplateToken(kind, position, name, $"{start}{name}");
throw CommandTemplateException.UnterminatedValueName(buffer.Original, token);
}
// Consume end of value character (> or ]).
buffer.Consume(end);
// Get the value (the text within the brackets).
var value = builder.ToString();
// Create a token and return it.
return new TemplateToken(kind, position, value, required ? $"<{value}>" : $"[{value}]");
}
}
}