-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Expose variable scope information tracked by the parser to consumers …
…via the ParserOptions.OnNode callback
- Loading branch information
Showing
17 changed files
with
542 additions
and
172 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,55 @@ | ||
using System; | ||
using Acornima.Ast; | ||
|
||
namespace Acornima; | ||
|
||
public static class ParserOptionsExtensions | ||
{ | ||
private static readonly OnNodeHandler s_parentSetter = node => | ||
public static TOptions RecordParentNodeInUserData<TOptions>(this TOptions options, bool enable = true) | ||
where TOptions : ParserOptions | ||
{ | ||
foreach (var child in node.ChildNodes) | ||
var helper = options._onNode?.Target as OnNodeHelper; | ||
if (enable) | ||
{ | ||
(helper ?? new OnNodeHelper()).EnableParentNodeRecoding(options); | ||
} | ||
else | ||
{ | ||
child.UserData = node; | ||
helper?.DisableParentNodeRecoding(options); | ||
} | ||
}; | ||
|
||
public static TOptions RecordParentNodeInUserData<TOptions>(this TOptions options, bool enable = true) | ||
where TOptions : ParserOptions | ||
return options; | ||
} | ||
|
||
private sealed class OnNodeHelper : IOnNodeHandlerWrapper | ||
{ | ||
options._onNode = (OnNodeHandler?)Delegate.RemoveAll(options._onNode, s_parentSetter); | ||
private OnNodeHandler? _onNode; | ||
public OnNodeHandler? OnNode { get => _onNode; set => _onNode = value; } | ||
|
||
if (enable) | ||
public void EnableParentNodeRecoding(ParserOptions options) | ||
{ | ||
options._onNode += s_parentSetter; | ||
if (!ReferenceEquals(options._onNode?.Target, this)) | ||
{ | ||
_onNode = options._onNode; | ||
options._onNode = SetParentNode; | ||
} | ||
} | ||
|
||
return options; | ||
public void DisableParentNodeRecoding(ParserOptions options) | ||
{ | ||
if (options._onNode == SetParentNode) | ||
{ | ||
options._onNode = _onNode; | ||
} | ||
} | ||
|
||
private void SetParentNode(Node node, OnNodeContext context) | ||
{ | ||
foreach (var child in node.ChildNodes) | ||
{ | ||
child.UserData = node; | ||
} | ||
|
||
_onNode?.Invoke(node, context); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
using System; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace Acornima.Helpers; | ||
|
||
/// <summary> | ||
/// A struct that can store a read-only managed reference. | ||
/// </summary> | ||
internal readonly ref struct ReadOnlyRef<T> | ||
{ | ||
#if NET7_0_OR_GREATER | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public ReadOnlyRef(ref readonly T value) | ||
{ | ||
Value = ref value; | ||
} | ||
|
||
public readonly ref readonly T Value; | ||
#else | ||
private readonly ReadOnlySpan<T> _value; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER | ||
public ReadOnlyRef(ref readonly T value) | ||
{ | ||
_value = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in value), 1); | ||
} | ||
#else | ||
public ReadOnlyRef(ReadOnlySpan<T> span, int index) | ||
{ | ||
_value = span.Slice(index, 1); | ||
} | ||
#endif | ||
|
||
public ref readonly T Value { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref MemoryMarshal.GetReference(_value); } | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System; | ||
using System.Runtime.CompilerServices; | ||
using Acornima.Helpers; | ||
|
||
namespace Acornima; | ||
|
||
using static ExceptionHelper; | ||
|
||
public readonly ref struct OnNodeContext | ||
{ | ||
internal readonly ReadOnlyRef<Scope> _scope; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
internal OnNodeContext(ReadOnlyRef<Scope> scope, ArrayList<Scope> scopeStack) | ||
{ | ||
_scope = scope; | ||
ScopeStack = scopeStack.AsReadOnlySpan(); | ||
} | ||
|
||
public bool HasScope { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => !Unsafe.IsNullRef(ref Unsafe.AsRef(in _scope.Value)); } | ||
|
||
public ref readonly Scope Scope | ||
{ | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
get | ||
{ | ||
ref readonly var scope = ref _scope.Value; | ||
if (Unsafe.IsNullRef(ref Unsafe.AsRef(in scope))) | ||
{ | ||
ThrowInvalidOperationException<object>(); | ||
} | ||
return ref scope; | ||
} | ||
} | ||
|
||
public ReadOnlySpan<Scope> ScopeStack { [MethodImpl(MethodImplOptions.AggressiveInlining)] get; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.