Skip to content

Instantly share code, notes, and snippets.

@acple
Created March 1, 2019 10:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save acple/9f511d5e6474111e42b4d54cdeae97c7 to your computer and use it in GitHub Desktop.
Save acple/9f511d5e6474111e42b4d54cdeae97c7 to your computer and use it in GitHub Desktop.
using System;
using ParsecSharp;
namespace ParsecSharp.Utils
{
public class DebugOutputStream<TToken> : IParsecStateStream<TToken>
{
public enum MoveState { Backward, Stay, Forward }
private class Cursor
{
private IPosition position;
public Cursor(IPosition position)
{
this.position = position;
}
public MoveState MoveTo(IPosition next)
{
var compare = next.CompareTo(this.position);
this.position = next;
return (compare < 0) ? MoveState.Backward : (0 < compare) ? MoveState.Forward : MoveState.Stay;
}
}
private readonly IParsecStateStream<TToken> _state;
private readonly Action<IParsecState<TToken>, MoveState> _getCurrent;
private readonly Action<IParsecState<TToken>, bool> _getNext;
private readonly Lazy<IParsecStateStream<TToken>> _next;
private readonly Cursor cursor; // mutable
public TToken Current => this.GetCurrent();
public bool HasValue => this._state.HasValue;
public IPosition Position => this._state.Position;
public IParsecStateStream<TToken> Next => this.GetNext();
public DebugOutputStream(IParsecStateStream<TToken> state) : this(state, StdOutGetCurrent, StdOutGetNext)
{ }
public DebugOutputStream(IParsecStateStream<TToken> state, Action<IParsecState<TToken>, MoveState> getCurrent) : this(state, getCurrent, getNext: null)
{ }
public DebugOutputStream(IParsecStateStream<TToken> state, Action<IParsecState<TToken>, bool> getNext) : this(state, getCurrent: null, getNext)
{ }
public DebugOutputStream(IParsecStateStream<TToken> state, Action<IParsecState<TToken>, MoveState> getCurrent, Action<IParsecState<TToken>, bool> getNext) : this(state, getCurrent, getNext, new Cursor(state.Position))
{ }
private DebugOutputStream(IParsecStateStream<TToken> state, Action<IParsecState<TToken>, MoveState> getCurrent, Action<IParsecState<TToken>, bool> getNext, Cursor cursor)
{
this._state = state;
this._getCurrent = getCurrent;
this._getNext = getNext;
this.cursor = cursor;
this._next = new Lazy<IParsecStateStream<TToken>>(() => new DebugOutputStream<TToken>(this._state.Next, this._getCurrent, this._getNext, cursor));
}
private TToken GetCurrent()
{
this._getCurrent?.Invoke(this._state, this.cursor.MoveTo(this._state.Position));
return this._state.Current;
}
private IParsecStateStream<TToken> GetNext()
{
this._getNext?.Invoke(this._state.Next, !this._next.IsValueCreated);
return this._next.Value;
}
public bool Equals(IParsecState<TToken> other)
=> ReferenceEquals(this, other);
public void Dispose()
=> this._state.Dispose();
public static void StdOutGetCurrent(IParsecState<TToken> state, MoveState move)
=> Console.WriteLine(DefaultGetCurrentToString(state, move));
public static string DefaultGetCurrentToString(IParsecState<TToken> state, MoveState move)
=> $"{((move is MoveState.Backward) ? "<<<" : (move is MoveState.Forward) ? ">>>" : "===")} GetCurrent ({state.Position}): {{ Current = '{state.Current?.ToString() ?? "null"}' }}";
public static void StdOutGetNext(IParsecState<TToken> state, bool isFirstCall)
=> Console.WriteLine(DefaultGetNextToString(state, isFirstCall));
public static string DefaultGetNextToString(IParsecState<TToken> state, bool isFirstCall)
=> $"GetNext ({state.Position}): {{ IsFirstCall = {isFirstCall}, EndOfInput = {!state.HasValue} }}";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment