Skip to content

Commit

Permalink
Implement 3+ token peeking storage strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
atifaziz committed Jul 12, 2022
1 parent dfd23cd commit ad82520
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 8 deletions.
46 changes: 44 additions & 2 deletions src/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace Gratt
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Unit = System.ValueTuple;

Expand Down Expand Up @@ -537,6 +538,9 @@ public override bool TryPush(ref Store store, T item)
}
}

T Pop(ref Store store) =>
TryPop(ref store, out var popped) ? popped : throw new InvalidOperationException();

public override bool TryPop(ref Store store, [MaybeNullWhen(false)] out T item)
{
switch (store)
Expand All @@ -557,8 +561,46 @@ public override bool TryPop(ref Store store, [MaybeNullWhen(false)] out T item)
}
}

public override ITokenStream<T> Grow(Store store, IEnumerator<T> enumerator) =>
throw new InvalidOperationException();
public override ITokenStream<T> Grow(Store store, IEnumerator<T> enumerator)
{
var stream = Create(enumerator, MultiTokenStackOps<T>.Instance);
Debug.Assert(store.Count == CountOf2.Two);
var (first, second) = (Pop(ref store), Pop(ref store));
stream.Unread(second);
stream.Unread(first);
return stream;
}
}

sealed class MultiTokenStackOps<T> : StoreStackOps<ITokenStream<T>, Stack<T>?, T>
{
public static readonly MultiTokenStackOps<T> Instance = new();

MultiTokenStackOps() { }

public override Stack<T>? Default => default;

public override bool TryPush(ref Stack<T>? store, T item)
{
store ??= new Stack<T>();
store.Push(item);
return true;
}

public override bool TryPop(ref Stack<T>? store, [MaybeNullWhen(false)] out T item)
{
if (store is not { Count: > 0 } stack)
{
item = default;
return false;
}

item = stack.Pop();
return true;
}

public override ITokenStream<T> Grow(Stack<T>? store, IEnumerator<T> enumerator) =>
throw new NotImplementedException(); // Should never get here!
}
}
}
14 changes: 8 additions & 6 deletions tests/ParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,22 @@ public void ReadAheadTwo()
public void ReadAheadMore()
{
var result =
Parse((TokenKind.Qux, "qux"), (TokenKind.Foo, "foo"),
(TokenKind.Bar, "bar"), (TokenKind.Baz, "baz"),
Parse((TokenKind.Foo, "foo"), (TokenKind.Bar, "bar"), (TokenKind.Baz, "baz"), (TokenKind.Qux, "qux"),
(TokenKind.Eoi, string.Empty));

Assert.That(result, Is.EqualTo("quxfoobarbaz"));
Assert.That(result, Is.EqualTo("foobarbazqux"));
}

static string Parse(params (TokenKind Kind, string Token)[] tokens) =>
Parser.Parse<TokenKind, string, int, string>(0, TokenKind.Eoi, _ => new(),
(_, _) =>
(token, parser)
=> parser.Peek() is (TokenKind.Foo, _)
&& parser.Peek(1) is (TokenKind.Bar, _)
&& parser.Peek(2) is (TokenKind.Baz, _) ? "quxfoobarbaz"
=> parser.Peek() is (TokenKind.Bar, _)
&& parser.Peek(1) is (TokenKind.Baz, _)
&& parser.Peek(2) is (TokenKind.Qux, _)
&& parser.Match(TokenKind.Bar)
&& parser.Match(TokenKind.Baz)
&& parser.Match(TokenKind.Qux)? "foobarbazqux"
: parser.Peek() is (TokenKind.Bar, _)
&& parser.Peek(1) is (TokenKind.Baz, _)
&& parser.Match(TokenKind.Bar)
Expand Down

0 comments on commit ad82520

Please sign in to comment.