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
|
/***************************************************************************************************
Copyright (C) 2024 The Qt Company Ltd.
SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
***************************************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QtVsTools.SyntaxAnalysis
{
public abstract partial class RegExpr
{
public class Pattern
{
public RegExpr Expr { get; set; }
public string ExprRender { get; set; }
public Dictionary<string, Token> Tokens { get; set; }
public Token Root { get; set; }
}
class Renderer
{
////////////////////////////////////////////////////////////////////////////////////////
///
/// RegExpr.Renderer.RenderPattern()
///
////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Transform the RegExpr representation of a regular expression into a pattern string
/// and a mapping of capture group id's into corresponding token definitions.
/// </summary>
/// <param name="rootExpr">RegExpr to render</param>
/// <param name="wsExpr">Default token white-space</param>
/// <returns>Pattern object containing pattern string and token map</returns>
public Pattern RenderPattern(RegExpr rootExpr, RegExpr wsExpr)
{
var pattern = new StringBuilder();
var rootToken = Token.CreateRoot();
var tokenStack = new Stack<Token>();
tokenStack.Push(rootToken);
var tokens = new HashSet<Token>();
var stack = new Stack<StackFrame>();
var mode = RenderMode.Default;
stack.Push(rootExpr);
while (stack.Any()) {
var context = stack.Pop();
if (context.Expr == null)
continue;
var expr = context.Expr;
IEnumerable<RegExpr> children = context.Children;
RegExpr parent = stack.Any() ? stack.Peek() : null;
if (expr is Token token)
tokens.Add(token);
if (children == null) {
children = expr.OnRender(wsExpr, parent, pattern, ref mode, tokenStack);
if (children != null && children.Any()) {
stack.Push(new StackFrame { Expr = expr, Children = children.Skip(1) });
stack.Push(children.First());
}
} else if (children.Any()) {
expr.OnRenderNext(wsExpr, parent, pattern, ref mode, tokenStack);
stack.Push(new StackFrame { Expr = expr, Children = children.Skip(1) });
stack.Push(children.First());
} else {
expr.OnRenderEnd(wsExpr, parent, pattern, ref mode, tokenStack);
}
}
var tokensByCaptureId = tokens
.SelectMany(token => token.CaptureIds
.Select(captureId => new { Id = captureId, Token = token }))
.ToDictionary(idToken => idToken.Id, idToken => idToken.Token);
tokensByCaptureId.Add(ParseTree.KeyRoot, rootToken);
return new Pattern
{
Expr = rootExpr,
ExprRender = pattern.ToString(),
Tokens = tokensByCaptureId,
Root = rootToken
};
}
class StackFrame
{
public RegExpr Expr { get; set; }
public IEnumerable<RegExpr> Children { get; set; }
public static implicit operator StackFrame(RegExpr expr)
{
return new StackFrame { Expr = expr };
}
public static implicit operator RegExpr(StackFrame frame)
{
return frame?.Expr;
}
}
}
}
}
|