yog-script-analyze 0.4.0

Yog Script (.ys, .yns) analyzed: its lexer, parser and syntax tree, names resolved, the class index model — what the build and the editors read a source with.
Documentation
namespace System.Logging;

using System.Threading;

/// The scopes begun in the code's flow (.NET's `LoggerExternalScopeProvider`):
/// each flow (an `async` method and what it awaits) its own, as `AsyncLocal` keeps them.
public readonly sealed class LoggerExternalScopeProvider : IExternalScopeProvider {
    private readonly AsyncLocal<LogScope?> _current = new AsyncLocal<LogScope?>();

    public readonly void ForEachScope<TState>(Action<object?, TState> callback, TState state) {
        Report(in _current.Value, callback, state);
    }

    /// `callback` of `scope`'s state, after its outer ones'.
    private static void Report<TState>(in LogScope? scope, Action<object?, TState> callback, TState state) {
        if (scope == null) {
            return;
        }
        Report(in scope.Parent, callback, state);
        callback(scope.State, state);
    }

    public readonly IDisposable Push(object? state) {
        let scope = new LogScope(this, move state, _current.Value);
        _current.Value = scope;
        return scope;
    }

    /// One scope begun: its state, the one it's in. Shared by the flow and
    /// whoever began it, so never changed but for being ended.
    private readonly sealed class LogScope : IDisposable {
        private readonly LoggerExternalScopeProvider _provider;
        private readonly Cell<bool> _disposed = new Cell<bool>(false);
        public readonly object? State;
        public readonly LogScope? Parent;

        public LogScope(LoggerExternalScopeProvider provider, object? state, LogScope? parent) {
            _provider = move provider;
            State = move state;
            Parent = move parent;
        }

        public override string? ToString() => State?.ToString();

        public void Dispose() {
            if (!_disposed.Replace(true)) {
                _provider._current.Value = Parent;
            }
        }
    }
}