-
Notifications
You must be signed in to change notification settings - Fork 3
/
Node.cs
98 lines (78 loc) · 4.09 KB
/
Node.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
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
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using Acornima.Helpers;
namespace Acornima.Ast;
// AST hierarchy is based on:
// * https://github.com/estree/estree
// * https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/estree
[DebuggerDisplay($"{{{nameof(GetDebugDisplayText)}(), nq}}")]
public abstract class Node : INode
{
protected Node(NodeType type)
{
Type = type;
}
public NodeType Type { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; }
public virtual string TypeText => Type.ToString();
public ChildNodes ChildNodes { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new ChildNodes(this); }
/// <remarks>
/// Inheritors who extend the AST with custom node types should override this method and provide an actual implementation.
/// </remarks>
protected internal virtual IEnumerator<Node>? GetChildNodes() => null;
internal virtual Node? NextChildNode(ref ChildNodes.Enumerator enumerator) =>
throw new NotImplementedException(string.Format(ExceptionMessages.OverrideGetChildNodes, nameof(GetChildNodes)));
public int Start { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _range.Start; }
public int End { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _range.End; }
internal Range _range;
public Range Range { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _range; init => _range = value; }
public ref readonly Range RangeRef { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref _range; }
internal SourceLocation _location;
public SourceLocation Location { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _location; init => _location = value; }
public ref readonly SourceLocation LocationRef { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref _location; }
private protected AdditionalDataSlot _additionalDataSlot;
/// <summary>
/// Gets or sets the arbitrary, user-defined data object associated with the current <see cref="Node"/>.
/// </summary>
/// <remarks>
/// The operation is not guaranteed to be thread-safe. In case concurrent access or update is possible, the necessary synchronization is caller's responsibility.
/// </remarks>
public object? UserData
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _additionalDataSlot.PrimaryData;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => _additionalDataSlot.PrimaryData = value;
}
protected internal abstract object? Accept(AstVisitor visitor);
/// <summary>
/// Dispatches the visitation of the current node to <see cref="AstVisitor.VisitExtension(Node)"/>.
/// </summary>
/// <remarks>
/// When defining custom node types, inheritors can use this method to implement the abstract <see cref="Accept(AstVisitor)"/> method.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected object? AcceptAsExtension(AstVisitor visitor)
{
return visitor.VisitExtension(this);
}
private static Func<Node, string>? s_toDebugDisplayText;
protected virtual string GetDebugDisplayText()
{
var toDebugDisplayText = LazyInitializer.EnsureInitialized(ref s_toDebugDisplayText, () =>
{
var astToJavaScriptType = System.Type.GetType("Acornima.AstToJavaScript, Acornima.Extras", throwOnError: false, ignoreCase: false);
if (astToJavaScriptType is not null
&& astToJavaScriptType.GetMethod("ToDebugDisplayText", BindingFlags.Static | BindingFlags.NonPublic, binder: null, new[] { typeof(Node) }, modifiers: null) is { } toDebugDisplayTextMethod)
{
try { return (Func<Node, string>)Delegate.CreateDelegate(typeof(Func<Node, string>), toDebugDisplayTextMethod); }
catch { /* intentional no-op */ }
}
return node => node.ToString()!;
});
return $"/*{TypeText}*/ {toDebugDisplayText!(this)}";
}
}