Parser rewrite
This commit is contained in:
@@ -1,29 +1,37 @@
|
||||
namespace ParadoxSaveParser.Lib;
|
||||
|
||||
public readonly record struct SearchArgs
|
||||
/// <summary>
|
||||
/// The node a search expression is tested against: its key inside the parent dictionary,
|
||||
/// still in the raw bytes of the save, and its position inside the parent list.
|
||||
/// Keys stay undecoded so that a key rejected by the query never becomes a string.
|
||||
/// </summary>
|
||||
public readonly ref struct MatchCandidate
|
||||
{
|
||||
public readonly string KeyStr;
|
||||
public readonly StringBuilder? KeySB;
|
||||
public readonly int LocalIndex;
|
||||
public readonly ReadOnlySpan<byte> Key;
|
||||
public readonly int Index;
|
||||
|
||||
public SearchArgs(int localIndex, string keyStr)
|
||||
/// <summary>Encoding <see cref="Key" /> is written in.</summary>
|
||||
public readonly Encoding Encoding;
|
||||
|
||||
/// <summary>A list item, which has a position but no key.</summary>
|
||||
public MatchCandidate(int index)
|
||||
{
|
||||
KeyStr = keyStr;
|
||||
KeySB = null;
|
||||
LocalIndex = localIndex;
|
||||
Key = default;
|
||||
Index = index;
|
||||
Encoding = Encoding.Latin1;
|
||||
}
|
||||
|
||||
public SearchArgs(int localIndex, StringBuilder keySb)
|
||||
|
||||
public MatchCandidate(int index, ReadOnlySpan<byte> key, Encoding encoding)
|
||||
{
|
||||
KeyStr = string.Empty;
|
||||
KeySB = keySb;
|
||||
LocalIndex = localIndex;
|
||||
Key = key;
|
||||
Index = index;
|
||||
Encoding = encoding;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ISearchExpression
|
||||
{
|
||||
bool DoesMatch(SearchArgs args, out ISearchExpression? nextSearchExpression);
|
||||
bool DoesMatch(MatchCandidate candidate, out ISearchExpression? nextSearchExpression);
|
||||
}
|
||||
|
||||
public static class SearchExpressionCompiler
|
||||
@@ -108,7 +116,7 @@ public static class SearchExpressionCompiler
|
||||
|
||||
private record AnyMatchExpression(ISearchExpression? next) : ISearchExpression
|
||||
{
|
||||
public bool DoesMatch(SearchArgs args, out ISearchExpression? nextSearchExpression)
|
||||
public bool DoesMatch(MatchCandidate candidate, out ISearchExpression? nextSearchExpression)
|
||||
{
|
||||
nextSearchExpression = next;
|
||||
return true;
|
||||
@@ -117,7 +125,7 @@ public static class SearchExpressionCompiler
|
||||
|
||||
private record NoMatchExpression : ISearchExpression
|
||||
{
|
||||
public bool DoesMatch(SearchArgs args, out ISearchExpression? nextSearchExpression)
|
||||
public bool DoesMatch(MatchCandidate candidate, out ISearchExpression? nextSearchExpression)
|
||||
{
|
||||
nextSearchExpression = null;
|
||||
return false;
|
||||
@@ -126,10 +134,10 @@ public static class SearchExpressionCompiler
|
||||
|
||||
private record MultipleMatchExpression(List<ISearchExpression> subExprs) : ISearchExpression
|
||||
{
|
||||
public bool DoesMatch(SearchArgs args, out ISearchExpression? nextSearchExpression)
|
||||
public bool DoesMatch(MatchCandidate candidate, out ISearchExpression? nextSearchExpression)
|
||||
{
|
||||
foreach (var e in subExprs)
|
||||
if (e.DoesMatch(args, out nextSearchExpression))
|
||||
if (e.DoesMatch(candidate, out nextSearchExpression))
|
||||
return true;
|
||||
|
||||
nextSearchExpression = null;
|
||||
@@ -139,9 +147,9 @@ public static class SearchExpressionCompiler
|
||||
|
||||
private record IndexMatchExpression(int index, ISearchExpression? next) : ISearchExpression
|
||||
{
|
||||
public bool DoesMatch(SearchArgs args, out ISearchExpression? nextSearchExpression)
|
||||
public bool DoesMatch(MatchCandidate candidate, out ISearchExpression? nextSearchExpression)
|
||||
{
|
||||
if (args.LocalIndex == index)
|
||||
if (candidate.Index == index)
|
||||
{
|
||||
nextSearchExpression = next;
|
||||
return true;
|
||||
@@ -154,9 +162,20 @@ public static class SearchExpressionCompiler
|
||||
|
||||
private record ExactMatchExpression(string key, ISearchExpression? next) : ISearchExpression
|
||||
{
|
||||
public bool DoesMatch(SearchArgs args, out ISearchExpression? nextSearchExpression)
|
||||
// the key is compared as bytes, so it is encoded once for whatever encoding the
|
||||
// parser reads the save in
|
||||
private byte[]? _keyBytes;
|
||||
private Encoding? _keyEncoding;
|
||||
|
||||
public bool DoesMatch(MatchCandidate candidate, out ISearchExpression? nextSearchExpression)
|
||||
{
|
||||
if ((args.KeySB != null && args.KeySB.Equals(key)) || args.KeyStr == key)
|
||||
if (!ReferenceEquals(_keyEncoding, candidate.Encoding))
|
||||
{
|
||||
_keyEncoding = candidate.Encoding;
|
||||
_keyBytes = candidate.Encoding.GetBytes(key);
|
||||
}
|
||||
|
||||
if (candidate.Key.SequenceEqual(_keyBytes))
|
||||
{
|
||||
nextSearchExpression = next;
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user