Forge
csharpcf25d736
1using System.Collections.Concurrent;
2using Eto.Parse;
3using Eto.Parse.Parsers;
4
5namespace CascadeIDE.Services.Presentation;
6
7/// <summary>
8/// Внутренняя грамматика одного экрана <c>( … )</c> через <see cref="Eto.Parse"/> (Fluent API, семантика как в EBNF ADR 0017).
9/// Внешний уровень (несколько <c>(screen)</c>, разделители между экранами) — по-прежнему в <see cref="PresentationParser"/>.
10/// </summary>
11internal static class PresentationInnerEtoGrammar
12{
13 private static readonly ConcurrentDictionary<PresentationGrammarTokens, Grammar> Cache = new();
14
15 /// <summary>Собирает грамматику «якорь с опциональным весом», повторённую через <see cref="PresentationGrammarTokens.ZoneSeparator"/>.</summary>
16 public static Grammar GetOrCreate(PresentationGrammarTokens grammar)
17 {
18 return Cache.GetOrAdd(grammar, Build);
19 }
20
21 private static Grammar Build(PresentationGrammarTokens g)
22 {
23 var zoneSep = Terminals.Literal(g.ZoneSeparator);
24 var anchor = BuildAnchorChoice(g).Named("anchor");
25
26 var digit = Terminals.Digit;
27 var intPart = digit.Repeat(1);
28 var frac = Terminals.Literal(".").Then(digit.Repeat(1));
29 var weight = intPart.Then(frac.Optional()).Named("weight");
30
31 var weighted = weight.Optional().Then(anchor).Named("slot");
32
33 var inner = weighted.Then(new RepeatParser(zoneSep.Then(weighted), 0));
34
35 var rule = inner.Then(Terminals.End);
36 // Без CharacterSetAlternations: иначе Eto.Parse 1.6.0 схлопывает P|F|M в один CharSet и падает в CharSetTerminal.Test.
37 return new Grammar(rule)
38 {
39 CaseSensitive = true,
40 EnableMatchEvents = false,
41 Optimizations = GrammarOptimizations.All & ~GrammarOptimizations.CharacterSetAlternations,
42 };
43 }
44
45 /// <summary>Длинные литералы первыми, затем односимвольные (как <see cref="PresentationParser"/>).</summary>
46 private static Parser BuildAnchorChoice(PresentationGrammarTokens g)
47 {
48 var pairs = new (string Token, PresentationAnchorKind K)[]
49 {
50 (g.PfdZoneIdentifier, PresentationAnchorKind.Pfd),
51 (g.ForwardZoneIdentifier, PresentationAnchorKind.Forward),
52 (g.MfdZoneIdentifier, PresentationAnchorKind.Mfd),
53 };
54
55 Array.Sort(pairs, static (a, b) => b.Token.Length.CompareTo(a.Token.Length));
56
57 Parser? chain = null;
58 foreach (var (token, _) in pairs)
59 {
60 if (token.Length == 0)
61 continue;
62
63 Parser p = token.Length == 1
64 ? Terminals.Set(char.ToUpperInvariant(token[0]), char.ToLowerInvariant(token[0]))
65 : Terminals.Literal(token);
66
67 chain = chain is null ? p : chain.Or(p);
68 }
69
70 return chain ?? Terminals.Set('\uFFFF');
71 }
72}
73
View only · write via MCP/CIDE