23 using System.Collections.Generic;
30 namespace Ntp.Analyzer.Config.Compiler
46 errors =
new List<string>();
49 private readonly List<string>
errors;
63 public IEnumerable<string> Errors => errors;
76 switch (tokenizer.GetNext().Symbol)
78 case Symbol.KeywordDatabase:
79 ParseDatabaseSection(node);
81 case Symbol.KeywordPermission:
82 ParsePermissionSection(node);
85 ParseNotifySection(node);
88 case Symbol.KeywordService:
89 ParseHeartbeatSection(node);
91 case Symbol.KeywordReading:
92 ParseReadingSection(node);
95 ParseLogSection(node);
97 case Symbol.KeywordListener:
98 ParseListenerSection(node);
100 case Symbol.KeywordServer:
101 ParseHostSection(node);
111 LogError(
"Unknown section.");
126 LogError($
"section {name} is already defined. Choose another name.");
136 string entry = $
"Error in line {tokenizer.LineNumber} column {tokenizer.ColumnNumber}: {error}";
142 var name = ParseSectionStart();
149 switch (tokenizer.GetNext().Symbol)
151 case Symbol.KeywordFrequency:
152 case Symbol.KeywordInitialRun:
153 case Symbol.KeywordFixedRun:
155 case Symbol.KeywordPageTitle:
156 case Symbol.KeywordServerId:
157 case Symbol.KeywordContentTitle:
161 case Symbol.KeywordPageTemplate:
162 ParseOption<PageThemeNode>(node,
new List<Symbol>
168 case Symbol.KeywordContent:
169 ParseContentSection(node);
171 case Symbol.KeywordDestinations:
172 ParseFileDestinationSection(node);
180 ParseSectionEnd(name);
182 AddToSymbolTable(name, node);
189 if (tokenizer.GetNext().Symbol !=
Symbol.OpeningBrace)
190 LogError(
"Content section should begin with an opening brace.");
195 var content =
new StringBuilder();
196 while ((token = tokenizer.GetNext()).
Symbol !=
Symbol.ClosingBrace)
197 content.Append(token.
Text);
205 var name = ParseSectionStart();
212 switch (tokenizer.GetNext().Symbol)
217 case Symbol.KeywordAddress:
218 case Symbol.KeywordHostAddress:
222 case Symbol.KeywordCreate:
223 case Symbol.KeywordUpgrade:
224 case Symbol.KeywordImport:
225 case Symbol.KeywordDatabaseName:
226 case Symbol.KeywordDatabaseUser:
227 case Symbol.KeywordDatabasePass:
228 case Symbol.KeywordConString:
229 case Symbol.KeywordCertFile:
230 case Symbol.KeywordCertPass:
231 case Symbol.KeywordConnectionTimeout:
232 case Symbol.KeywordProtocol:
233 case Symbol.KeywordEnableSsl:
236 case Symbol.KeywordDatabaseProvider:
237 ParseOption<DatabaseProviderNode>(node,
new List<Symbol>
239 Symbol.KeywordDatabaseProviderMySql,
240 Symbol.KeywordDatabaseProviderPostgre
243 case Symbol.KeywordSslMode:
244 ParseOption<DatabaseProviderNode>(node,
new List<Symbol>
256 ParseSectionEnd(name);
265 tokenizer.ConsumeWhiteSpaces();
267 LogError(
"Expected end of line.");
272 var name = ParseSectionStart();
279 switch (tokenizer.GetNext().Symbol)
281 case Symbol.KeywordPrefix:
282 case Symbol.KeywordDirectory:
291 ParseSectionEnd(name);
297 var name = ParseSectionStart();
304 if (tokenizer.GetNext().Symbol ==
Symbol.KeywordFile)
310 ParseSectionEnd(name);
316 var name = ParseSectionStart();
323 switch (tokenizer.GetNext().Symbol)
326 case Symbol.KeywordLinkIndex:
336 ParseSectionEnd(name);
342 var name = ParseSectionStart();
349 if (tokenizer.GetNext().Symbol ==
Symbol.KeywordHeartbeat)
355 ParseSectionEnd(name);
361 var name = ParseSectionStart();
368 switch (tokenizer.GetNext().Symbol)
370 case Symbol.KeywordFrequency:
371 case Symbol.KeywordInitialRun:
372 case Symbol.KeywordFixedRun:
373 case Symbol.KeywordGraphPage:
374 case Symbol.KeywordLinkIndex:
378 case Symbol.KeywordDestinations:
379 ParseDirectoryDestinationSection(node);
387 ParseSectionEnd(name);
389 AddToSymbolTable(name, node);
398 var name = ParseSectionStart();
405 switch (tokenizer.GetNext().Symbol)
407 case Symbol.KeywordFrequency:
408 case Symbol.KeywordInitialRun:
409 case Symbol.KeywordFixedRun:
412 case Symbol.KeywordHeight:
413 case Symbol.KeywordTimespan:
414 case Symbol.KeywordFilterFactor:
415 case Symbol.KeywordJitter:
416 case Symbol.KeywordOffset:
417 case Symbol.KeywordGraphFrequency:
418 case Symbol.KeywordGraphStability:
421 case Symbol.KeywordDestinations:
422 ParseFileDestinationSection(node);
424 case Symbol.KeywordWebLinks:
425 ParseWebLinkSection(node);
427 case Symbol.KeywordGraphTime:
428 case Symbol.KeywordTimeStamp:
429 ParseOption<TimeStampNode>(node,
new List<Symbol>
431 Symbol.KeywordTimeStampLocal,
432 Symbol.KeywordTimeStampUtc
441 ParseSectionEnd(name);
443 AddToSymbolTable(name, node);
452 var name = ParseSectionStart();
459 switch (tokenizer.GetNext().Symbol)
461 case Symbol.KeywordFrequency:
462 case Symbol.KeywordInitialRun:
463 case Symbol.KeywordFixedRun:
464 case Symbol.KeywordPageTitle:
466 case Symbol.KeywordPoolMember:
467 case Symbol.KeywordQueryDirect:
468 case Symbol.KeywordPeerPage:
471 case Symbol.KeywordPageTemplate:
472 ParseOption<PageThemeNode>(node,
new List<Symbol>
478 case Symbol.KeywordPageTime:
479 case Symbol.KeywordTimeStamp:
480 ParseOption<TimeStampNode>(node,
new List<Symbol>
482 Symbol.KeywordTimeStampLocal,
483 Symbol.KeywordTimeStampUtc
486 case Symbol.KeywordGraphSet:
487 ParseGraphSetSection(node);
489 case Symbol.KeywordSummaries:
490 ParseSummariesSection(node);
492 case Symbol.KeywordDestinations:
493 ParseFileDestinationSection(node);
501 ParseSectionEnd(name);
503 AddToSymbolTable(name, node);
508 var name = ParseSectionStart();
515 switch (tokenizer.GetNext().Symbol)
517 case Symbol.KeywordHostId:
519 case Symbol.KeywordAddress:
520 case Symbol.KeywordHostAddress:
521 case Symbol.KeywordFilePath:
522 case Symbol.KeywordWebPath:
525 case Symbol.KeywordHostType:
526 ParseOption<HostTypeNode>(node,
new List<Symbol>
533 case Symbol.KeywordTimeStamp:
534 ParseOption<TimeStampNode>(node,
new List<Symbol>
536 Symbol.KeywordTimeStampLocal,
537 Symbol.KeywordTimeStampUtc
540 case Symbol.KeywordAboutPage:
541 ParseAboutPageSection(node);
543 case Symbol.KeywordHostPage:
544 ParseHostPageSection(node);
546 case Symbol.KeywordPeerPage:
547 ParsePeerPageSection(node);
549 case Symbol.KeywordHostGraph:
550 ParseHostGraphSection(node);
552 case Symbol.KeywordPeerGraph:
553 ParsePeerGraphSection(node);
555 case Symbol.KeywordTrafficGraph:
556 ParseTrafficGraphSection(node);
558 case Symbol.KeywordPeerSummaryPage:
559 ParsePeerSummaryPageSection(node);
561 case Symbol.KeywordHostGraphPage:
562 ParseHostGraphPageSection(node);
564 case Symbol.KeywordPeerGraphPage:
565 ParsePeerGraphPageSection(node);
568 ParseMenuSection(node);
570 case Symbol.KeywordHostStats:
571 case Symbol.KeywordHostIoStats:
572 case Symbol.KeywordPeerStats:
573 case Symbol.KeywordDriftStats:
574 ParseStatSection(node);
582 ParseSectionEnd(name);
589 tokenizer.ConsumeWhiteSpaces();
590 var token = tokenizer.GetNext();
592 switch (token.TokenType)
602 LogError($
"{keyword.Name} must be either an integer or a string.");
609 var name = ParseSectionStart();
616 var token = tokenizer.GetNext();
618 switch (token.Symbol)
632 ParseSectionEnd(name);
638 var name = ParseSectionStart();
645 switch (tokenizer.GetNext().Symbol)
648 ParseOption<LogTypeNode>(node,
new List<Symbol>
655 case Symbol.KeywordSeverity:
656 ParseOption<SeverityNode>(node,
new List<Symbol>
666 case Symbol.KeywordShowTimestamp:
667 case Symbol.KeywordShowSeverity:
668 case Symbol.KeywordTimeFormat:
678 ParseSectionEnd(name);
684 var name = ParseSectionStart();
691 switch (tokenizer.GetNext().Symbol)
694 case Symbol.KeywordCaption:
696 case Symbol.KeywordDropdown:
700 ParseMenuItemType(node);
702 case Symbol.KeywordContent:
703 ParseMenuSection(node);
711 ParseSectionEnd(name);
718 var token = tokenizer.GetNext();
720 switch (token.Symbol)
725 case Symbol.KeywordSpacer:
726 case Symbol.KeywordHeader:
729 case Symbol.KeywordDropdown:
740 var name = ParseSectionStart();
747 if (tokenizer.GetNext().Symbol ==
Symbol.KeywordItem)
753 ParseSectionEnd(name);
759 var name = ParseSectionStart();
766 switch (tokenizer.GetNext().Symbol)
768 case Symbol.KeywordFrequency:
769 case Symbol.KeywordInitialRun:
770 case Symbol.KeywordFixedRun:
775 case Symbol.KeywordAddress:
776 case Symbol.KeywordHostAddress:
778 case Symbol.KeywordEnableSsl:
779 case Symbol.KeywordSender:
781 case Symbol.KeywordRecipient:
782 case Symbol.KeywordSubject:
783 case Symbol.KeywordSmtpHost:
784 case Symbol.KeywordSmtpPort:
785 case Symbol.KeywordSmtpUser:
786 case Symbol.KeywordSmtpPass:
795 ParseSectionEnd(name);
804 private void ParseOption<T>(
ISyntaxNode node, List<Symbol> options)
807 tokenizer.ConsumeWhiteSpaces();
808 var token = tokenizer.GetNext();
810 if (options.Contains(token.Symbol))
811 node.
Add(
new T {Value = token.Symbol});
815 LogError($
"Invalid value for option {keyword}");
823 var name = ParseSectionStart();
830 switch (tokenizer.GetNext().Symbol)
832 case Symbol.KeywordFrequency:
833 case Symbol.KeywordInitialRun:
834 case Symbol.KeywordFixedRun:
835 case Symbol.KeywordGraphPage:
836 case Symbol.KeywordLinkIndex:
840 case Symbol.KeywordDestinations:
841 ParseDirectoryDestinationSection(node);
849 ParseSectionEnd(name);
851 AddToSymbolTable(name, node);
860 var name = ParseSectionStart();
867 switch (tokenizer.GetNext().Symbol)
869 case Symbol.KeywordFrequency:
870 case Symbol.KeywordInitialRun:
871 case Symbol.KeywordFixedRun:
874 case Symbol.KeywordHeight:
875 case Symbol.KeywordTimespan:
876 case Symbol.KeywordFilterFactor:
877 case Symbol.KeywordJitter:
878 case Symbol.KeywordOffset:
879 case Symbol.KeywordGraphBalance:
880 case Symbol.KeywordGraphDelay:
883 case Symbol.KeywordDestinations:
884 ParseDirectoryDestinationSection(node);
886 case Symbol.KeywordWebLinks:
887 ParseWebLinkSection(node);
889 case Symbol.KeywordGraphTime:
890 case Symbol.KeywordTimeStamp:
891 ParseOption<TimeStampNode>(node,
new List<Symbol>
893 Symbol.KeywordTimeStampLocal,
894 Symbol.KeywordTimeStampUtc
903 ParseSectionEnd(name);
905 AddToSymbolTable(name, node);
910 var name = ParseSectionStart();
917 switch (tokenizer.GetNext().Symbol)
919 case Symbol.KeywordFrequency:
920 case Symbol.KeywordInitialRun:
921 case Symbol.KeywordFixedRun:
923 case Symbol.KeywordPageTitle:
927 case Symbol.KeywordPageTemplate:
928 ParseOption<PageThemeNode>(node,
new List<Symbol>
934 case Symbol.KeywordTimeStamp:
935 case Symbol.KeywordPageTime:
936 ParseOption<TimeStampNode>(node,
new List<Symbol>
938 Symbol.KeywordTimeStampLocal,
939 Symbol.KeywordTimeStampUtc
942 case Symbol.KeywordGraphSet:
943 ParseGraphSetSection(node);
945 case Symbol.KeywordDestinations:
946 ParseDirectoryDestinationSection(node);
954 ParseSectionEnd(name);
956 AddToSymbolTable(name, node);
961 var name = ParseSectionStart();
968 switch (tokenizer.GetNext().Symbol)
970 case Symbol.KeywordFrequency:
971 case Symbol.KeywordInitialRun:
972 case Symbol.KeywordFixedRun:
974 case Symbol.KeywordPageTitle:
975 case Symbol.KeywordPeerPage:
979 case Symbol.KeywordPageTemplate:
980 ParseOption<PageThemeNode>(node,
new List<Symbol>
986 case Symbol.KeywordGraphSet:
987 ParseGraphSetSection(node);
989 case Symbol.KeywordDestinations:
990 ParseFileDestinationSection(node);
998 ParseSectionEnd(name);
1000 AddToSymbolTable(name, node);
1005 var name = ParseSectionStart();
1011 tokenizer.Consume();
1012 switch (tokenizer.GetNext().Symbol)
1015 case Symbol.KeywordExecUser:
1016 case Symbol.KeywordGroup:
1017 ParseIntOrString(node);
1028 ParseSectionEnd(name);
1034 var name = ParseSectionStart();
1040 tokenizer.Consume();
1041 switch (tokenizer.GetNext().Symbol)
1045 if (nameNode != null)
1046 name = nameNode.
Value;
1048 case Symbol.KeywordFrequency:
1049 case Symbol.KeywordInitialRun:
1050 case Symbol.KeywordFixedRun:
1053 case Symbol.KeywordTimeStamp:
1054 ParseOption<TimeStampNode>(node,
new List<Symbol>
1056 Symbol.KeywordTimeStampLocal,
1057 Symbol.KeywordTimeStampUtc
1066 ParseSectionEnd(name);
1068 AddToSymbolTable(name, node);
1077 if (tokenizer.Token.Symbol ==
Symbol.ClosingBrace)
1080 tokenizer.ConsumeWhiteSpaces();
1081 if (tokenizer.GetNext().Symbol ==
Symbol.ClosingBrace)
1084 string errorName =
string.IsNullOrWhiteSpace(name)
1088 LogError($
"Configuration section {errorName}has unexpected content.");
1097 tokenizer.Consume();
1098 var token = tokenizer.GetNext();
1104 tokenizer.Consume();
1105 token = tokenizer.GetNext();
1108 if (token.Symbol !=
Symbol.OpeningBrace)
1109 LogError(
"Configuration section should begin with an opening brace.");
1120 var symbol = tokenizer.Token.Symbol;
1121 var name = ParseSectionStart();
1122 var node =
new StatSyntaxNode(symbol, name, tokenizer.LineNumber);
1127 tokenizer.Consume();
1128 switch (tokenizer.GetNext().Symbol)
1130 case Symbol.KeywordInitialRun:
1131 case Symbol.KeywordFixedRun:
1135 case Symbol.KeywordFrequency:
1136 ParseIntOrString(node);
1138 case Symbol.KeywordTimeStamp:
1139 ParseOption<TimeStampNode>(node,
new List<Symbol>
1141 Symbol.KeywordTimeStampLocal,
1142 Symbol.KeywordTimeStampUtc
1151 ParseSectionEnd(name);
1157 var name = ParseSectionStart();
1163 tokenizer.Consume();
1164 if (tokenizer.GetNext().Symbol ==
Symbol.KeywordPeerSummaryPage)
1170 ParseSectionEnd(name);
1180 var name = ParseSectionStart();
1186 tokenizer.Consume();
1187 switch (tokenizer.GetNext().Symbol)
1189 case Symbol.KeywordFrequency:
1190 case Symbol.KeywordInitialRun:
1191 case Symbol.KeywordFixedRun:
1192 case Symbol.KeywordTitle:
1193 case Symbol.KeywordWidth:
1194 case Symbol.KeywordHeight:
1195 case Symbol.KeywordTimespan:
1196 case Symbol.KeywordGraphReceived:
1197 case Symbol.KeywordGraphIgnored:
1198 case Symbol.KeywordGraphDropped:
1199 case Symbol.KeywordGraphSent:
1200 case Symbol.KeywordGraphNotSent:
1201 case Symbol.KeywordGraphAvgReceived:
1202 case Symbol.KeywordGraphAvgIgnored:
1203 case Symbol.KeywordGraphAvgDropped:
1204 case Symbol.KeywordGraphAvgSent:
1205 case Symbol.KeywordGraphAvgNotSent:
1206 case Symbol.KeywordGraphPlotInterval:
1207 case Symbol.KeywordGraphPacketRate:
1210 case Symbol.KeywordDestinations:
1211 ParseFileDestinationSection(node);
1213 case Symbol.KeywordWebLinks:
1214 ParseWebLinkSection(node);
1216 case Symbol.KeywordGraphTime:
1217 case Symbol.KeywordTimeStamp:
1218 ParseOption<TimeStampNode>(node,
new List<Symbol>
1220 Symbol.KeywordTimeStampLocal,
1221 Symbol.KeywordTimeStampUtc
1230 ParseSectionEnd(name);
1232 AddToSymbolTable(name, node);
1241 var keyword = ((
KeywordToken) tokenizer.Token).Keyword;
1242 tokenizer.ConsumeWhiteSpaces();
1243 var token = tokenizer.GetNext();
1246 if (keyword.ValueType == typeof(
string) && token.IsText)
1248 else if (keyword.ValueType == typeof(
string) && token ==
Token.
NewLine)
1250 else if (keyword.ValueType == typeof(
int) && token.TokenType ==
TokenType.IntegerValue)
1252 else if (keyword.ValueType == typeof(
int) && token.
Symbol ==
Symbol.Zero)
1254 else if (keyword.ValueType == typeof(
int) && token.
Symbol ==
Symbol.One)
1256 else if (keyword.ValueType == typeof(
double) && token.
TokenType ==
TokenType.NumericValue)
1258 else if (keyword.ValueType == typeof(
double) && token.
TokenType ==
TokenType.IntegerValue)
1260 else if (keyword.ValueType == typeof(
double) && token.
Symbol ==
Symbol.Zero)
1262 else if (keyword.ValueType == typeof(
double) && token.
Symbol ==
Symbol.One)
1264 else if (keyword.ValueType == typeof(
bool) &&
1267 else if (keyword.ValueType == typeof(
bool) &&
1272 LogError($
"Invalid value for setting {keyword.Name}");
1284 var name = ParseSectionStart();
1290 tokenizer.Consume();
1291 if (tokenizer.GetNext().Symbol ==
Symbol.KeywordLink)
1297 ParseSectionEnd(name);
void AddToSymbolTable(string name, ISyntaxNode node)
void ParseHostGraphSection(ISyntaxNode parent)
Parses a host graph configuration section.
void ParseHostGraphPageSection(ISyntaxNode parent)
void Execute()
Execute the parser stage.
void LogError(string error)
void ParsePeerPageSection(ISyntaxNode parent)
void ParseSectionEnd(string name)
Parses the footer of a configuration section.
void ParseLogSection(ISyntaxNode parent)
readonly ISyntaxNode root
override TokenType TokenType
readonly List< string > errors
void ParseFileDestinationSection(ISyntaxNode parent)
void ParseContentSection(ISyntaxNode parent)
ISyntaxNode ParseValue(ISyntaxNode parent)
Parses the value of a setting.
void ParseMenuItem(ISyntaxNode parent)
void ParseGraphSetSection(ISyntaxNode parent)
void ParseMenuSection(ISyntaxNode parent)
string ParseSectionStart()
Get the header of a configuration section.
void ParseNotifySection(ISyntaxNode parent)
void ParseWebLinkSection(ISyntaxNode parent)
void ParseReadingSection(ISyntaxNode parent)
void Add(ISyntaxNode node)
void ParseHostPageSection(ISyntaxNode parent)
Parses a host page configuration section.
void ParseHostSection(ISyntaxNode parent)
void ParseTrafficGraphSection(ISyntaxNode parent)
Parses a traffic graph configuration section.
void ParsePermissionSection(ISyntaxNode parent)
ConfigParser(string file, ISyntaxNode root)
Initializes a new instance of the ConfigParser class.
void ParsePeerSummaryPageSection(ISyntaxNode parent)
void ParseSummariesSection(ISyntaxNode parent)
void Add(string name, ISyntaxNode node)
void ParseAboutPageSection(ISyntaxNode parent)
void ParseHeartbeatSection(ISyntaxNode parent)
void ParsePeerGraphPageSection(ISyntaxNode parent)
void ParseListenerSection(ISyntaxNode parent)
void ParseDirectoryDestinationSection(ISyntaxNode parent)
void Add(ISyntaxNode node)
readonly Tokenizer tokenizer
void ParsePeerGraphSection(ISyntaxNode parent)
Parses a peer graph configuration section.
void ParseMenuItemType(ISyntaxNode node)
override TokenType TokenType
void ParseStatSection(ISyntaxNode parent)
Parses the stat configuration section.
The config parser transforms configuration texts into a syntax tree.
ISyntaxNode Lookup(string name)
void ParseIntOrString(ISyntaxNode parent)
void ParseDatabaseSection(ISyntaxNode parent)