-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathParserNode.cs
71 lines (61 loc) · 2.42 KB
/
ParserNode.cs
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
using System.Collections.Generic;
namespace Ara3D.Parakeet
{
/// <summary>
/// A node generated from a "NodeRule". A "NodeRule" will create two nodes
/// one when it starts (with no previous), and one when it ends.
/// These nodes are stored as a linked list, and can be converted
/// to a tree representation after all parsing is completed.
/// </summary>
public class ParserNode : ILocation
{
public readonly ParserRange Range;
public int Start => Range.BeginPosition;
public int End => Range.EndPosition;
public int Length => Range.Length;
public readonly string Name;
public readonly ParserNode Previous;
public string Contents => Range.Text;
public bool IsBegin => Range.Begin == null;
public bool IsEnd => Range.Begin != null;
public ParserRange GetRange()
=> Range;
public override string ToString()
=> $"({Name}:{Start}-{End}:{EllidedContents} end:{IsEnd})";
public const int MaxLength = 20;
public string EllidedContents
=> Contents.Length < MaxLength
? Contents : $"{Contents.Substring(0, MaxLength - 1)}...";
public ParserNode(string name, ParserRange range, ParserNode previous = null)
=> (Name, Range, Previous) = (name, range, previous);
public ParserTreeNode ToParseTree()
=> ToParseTreeAndNode().Item1;
public (ParserTreeNode, ParserNode) ToParseTreeAndNode()
{
var node = this;
var prev = node.Previous;
var children = new List<ParserTreeNode>();
while (prev != null && node.IsParentOf(prev))
{
ParserTreeNode child;
if (prev.IsBegin)
{
prev = prev.Previous;
continue;
}
(child, prev) = prev.ToParseTreeAndNode();
children.Add(child);
}
children.Reverse();
return (new ParserTreeNode(node, children), prev);
}
public IEnumerable<ParserNode> AllEndAllNodesReversed()
{
for (var node = this; node != null; node = node.Previous)
if (node.IsEnd)
yield return node;
}
public bool IsParentOf(ParserNode other)
=> Start <= other.Start && End >= other.End;
}
}