in src/Kusto.Language/Parser/Grammars/GrammarParser.cs [102:282]
private static Parser<char, Grammar> CreateParser()
{
// build the parser that parsers the simple grammar grammar
Parser<char, Grammar> elementCore = null;
var element = Forward(() => elementCore);
var WhitespaceCount =
Count(ZeroOrMore(Whitespace));
Parser<char, string> TokenText(string text) =>
Convert(Chars(text), text);
var IdentifierScan =
And(Or(Letter, Char('_')), ZeroOrMore(Or(Letter, Digit, Char('_'), Char('-'))));
var IdentifierText =
Text(IdentifierScan);
var IdentifierTextAndOffset =
TextAndOffset(IdentifierScan);
var StringLiteralScan =
And(Char('\''), ZeroOrMore(Not(Char('\''))), Char('\''));
var StringLiteralText =
Text(StringLiteralScan);
var StringLiteralTextAndOffset =
TextAndOffset(StringLiteralScan);
Parser<char, string> Token(string text) =>
Rule(WhitespaceCount, TokenText(text), (ws, tx) => tx);
var Identifier =
Rule(WhitespaceCount, IdentifierText, (ws, tx) => tx);
var IdentifierAndOffset =
Rule(WhitespaceCount, IdentifierTextAndOffset, (ws, tx) => tx);
var StringLiteral =
Rule(WhitespaceCount, StringLiteralText, (ws, tx) => tx);
var StringLiteralAndOffset =
Rule(WhitespaceCount, StringLiteralTextAndOffset, (ws, tx) => tx);
var term =
First(
Rule(Identifier, text => (Grammar)new TokenGrammar(text)),
Rule(StringLiteral, text => (Grammar)new TokenGrammar(KustoFacts.GetStringLiteralValue(text))))
.WithTag("<term>");
var rule =
Rule(
Token("<"), Text(OneOrMore(Not(Token(">")))), Token(">"),
(open, name, close) => (Grammar)new RuleGrammar(name))
.WithTag("<rule>");
var sequence = Produce(
OneOrMore(element),
(IReadOnlyList<Grammar> list) =>
list.Count == 1 ? list[0] : new SequenceGrammar(list.ToList()))
.WithTag("<sequence>");
var alternation =
List(
elementParser: sequence,
separatorParser: Token("|"),
missingElement: null,
missingSeparator: null,
endOfList: null,
oneOrMore: true,
allowTrailingSeparator: false,
producer: list =>
{
if (list.Count == 1)
{
return list[0].Element;
}
else
{
return new AlternationGrammar(list.Select(eas => eas.Element).OfType<Grammar>().ToArray());
}
}).WithTag("<alternation>");
var separator = Rule(
Token(","),
term,
Optional(Token("~")),
(comma, word, plus) => new SeparatorInfo(word, plus != null));
var repeatition = Rule(
Token("{"),
alternation,
Optional(separator),
Token("}"),
Optional(First(Token("+"), Token("*"))),
(open, elem, sep, close, kind) =>
{
var zeroOrMore = kind == null || kind == "*";
if (zeroOrMore)
{
return (Grammar)new ZeroOrMoreGrammar(elem, sep?.Separator, sep?.AllowTrailing ?? false);
}
else
{
return (Grammar)new OneOrMoreGrammar(elem, sep?.Separator, sep?.AllowTrailing ?? false);
}
}).WithTag("<repetition>");
var grouped = Rule(
Token("("), alternation, Token(")"),
(open, grammar, close) => grammar)
.WithTag("<grouping>");
var optional = Rule(
Token("["), alternation, Token("]"),
(open, optioned, close) => (Grammar)new OptionalGrammar(optioned))
.WithTag("<optional>");
var primaryElement =
First(
term, // id or 'id'
rule, // <rule>
grouped) // ( ... )
.WithTag("<element>");
// allow for some postfix abbreviations here
var postfixPrimary =
First(
optional, // [a]
repeatition, // {a}
ApplyOptional(
primaryElement,
_left =>
First(
Rule(_left, Token("!"),
(left, bang) => (Grammar)new RequiredGrammar(left))
.WithTag("<required>"),
// alternative to []
Rule(_left, Token("?"),
(left, question) => (Grammar)new OptionalGrammar(left))
.WithTag("<optional>"),
// alternative to { }*
Rule(_left, Token("*"),
(left, star) => (Grammar)new ZeroOrMoreGrammar(left))
.WithTag("<zero-or-more>"),
// alternative to { }+
Rule(_left, Token("+"),
(left, plus) => (Grammar)new OneOrMoreGrammar(left))
.WithTag("<one-or-more>")
)));
var hiddenPrimary =
First(
Rule(Token("#"), postfixPrimary,
(hat, hidden) => (Grammar)new HiddenGrammar(hidden)).WithTag("<hidden>"),
postfixPrimary);
// allow for tag=elem
var taggedPrimary =
First(
If(And(Identifier, Token("=")),
Rule(Identifier, Token("="), hiddenPrimary,
(id, eq, elem) => (Grammar)new TaggedGrammar(id, elem))),
If(And(StringLiteral, Token("=")),
Rule(StringLiteral, Token("="), hiddenPrimary,
(str, eq, elem) => (Grammar)new TaggedGrammar(KustoFacts.GetStringLiteralValue(str), elem))),
hiddenPrimary
);
elementCore = taggedPrimary;
return alternation;
}