Skip to content

Instantly share code, notes, and snippets.

@VladD2
Created April 22, 2025 21:57
Show Gist options
  • Save VladD2/cecd8f4c6919183455b7aeab87b7771d to your computer and use it in GitHub Desktop.
Save VladD2/cecd8f4c6919183455b7aeab87b7771d to your computer and use it in GitHub Desktop.
AST грамматики динамически расширяемого парсера
public abstract record Rule(string Kind)
{
public abstract override string ToString();
public virtual Rule InlineReferences(Dictionary<string, Rule> inlineableRules) => this;
}
public abstract record Terminal(string Kind) : Rule(Kind)
{
public override Rule InlineReferences(Dictionary<string, Rule> inlineableRules) => this;
public abstract int TryMatch(string input, int position);
}
public sealed record Literal(string Value, string? Kind = null) : Terminal(Kind ?? Value)
{
public override Rule InlineReferences(Dictionary<string, Rule> inlineableRules) => this;
public override int TryMatch(string input, int position) =>
input.AsSpan(position).StartsWith(Value, StringComparison.Ordinal) ? Value.Length : 0;
}
public record Seq(Rule[] Elements, string Kind) : Rule(Kind)
{
public override string ToString() => string.Join(" ", Elements.Select(e => e is Choice ? $"({e})" : e.ToString()));
public override Rule InlineReferences(Dictionary<string, Rule> inlineableRules) =>
new Seq(Elements.Select(e => e.InlineReferences(inlineableRules)).ToArray(), Kind);
}
public record Choice(Rule[] Alternatives, string? Kind = null) : Rule(Kind ?? nameof(Choice))
{
public override string ToString() => string.Join<Rule>(" | ", Alternatives);
public override Rule InlineReferences(Dictionary<string, Rule> inlineableRules) =>
new Choice(Alternatives.Select(a => a.InlineReferences(inlineableRules)).ToArray(), Kind);
}
public record OneOrMany(Rule Element, string? Kind = null) : Rule(Kind ?? nameof(OneOrMany))
{
public override string ToString() => $"{Element}+";
public override Rule InlineReferences(Dictionary<string, Rule> inlineableRules) =>
new OneOrMany(Element.InlineReferences(inlineableRules), Kind);
}
public record ZeroOrMany(Rule Element, string? Kind = null) : Rule(Kind ?? nameof(ZeroOrMany))
{
public override string ToString() => $"{Element}*";
public override Rule InlineReferences(Dictionary<string, Rule> inlineableRules) =>
new ZeroOrMany(Element.InlineReferences(inlineableRules), Kind);
}
public record Optional(Rule Element, string? Kind = null) : Rule(Kind ?? nameof(Optional))
{
public override string ToString() => $"{Element}?";
public override Rule InlineReferences(Dictionary<string, Rule> inlineableRules) =>
new Optional(Element.InlineReferences(inlineableRules), Kind);
}
public record Ref(string RuleName, string? Kind = null) : Rule(Kind ?? nameof(RuleName))
{
public override string ToString() => RuleName;
public override Rule InlineReferences(Dictionary<string, Rule> inlineableRules) =>
inlineableRules.TryGetValue(RuleName, out var rule) ? rule.InlineReferences(inlineableRules) : this;
}
public record ReqRef(string RuleName, int Precedence = 0, bool Right = false, string? Kind = null) : Rule(Kind ?? nameof(RuleName))
{
public override string ToString() => $"{RuleName} {{{Precedence}, {(Right ? "left" : "right")}}}";
public override Rule InlineReferences(Dictionary<string, Rule> inlineableRules) => this;
}
public record RuleWithPrecedence(string Kind, Seq Seq, int Precedence, bool Right);
public record TdoppRule(
Ref Name,
string Kind,
Rule[] Prefix,
RuleWithPrecedence[] Postfix
) : Rule(Kind)
{
public override string ToString() =>
$"{Name} = Prefix: {string.Join<Rule>(" | ", Prefix)}" +
$" Postfix: {string.Join("", Postfix.Select(x => $" {{{x.Precedence}{(x.Right ? "" : " right")}}} {x.Seq}"))}";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment