refactored SearchExpression

This commit is contained in:
2026-09-15 13:18:09 +02:00
parent 1d53f6930a
commit 5b1b8f4ce5
21 changed files with 509 additions and 216 deletions
+17 -8
View File
@@ -14,13 +14,20 @@ public class SaveParserEU4
private const int DefaultBufferSize = 64 * 1024;
private static ReadOnlySpan<byte> Header => "EU4txt"u8;
/// <summary>
/// Windows-1252 is the default encoding of the save files
/// </summary>
public static Encoding DefaultEncoding => ParadoxEncodings.Windows1252;
private readonly Tokenizer _tokens;
private readonly SearchExpressionCompilation? _query;
// step of the query the parser is currently at, compiled by Parse()
private ISearchExpression? _searchExprCurrent;
/// <summary>
/// Encoding of the strings inside the save. Saves of different localizations use
/// different ones, so it can be changed; <see cref="System.Text.Encoding.Latin1" /> maps
/// every byte to one character and never fails, which makes it a safe default.
/// different ones, so it can be changed; <see cref="DefaultEncoding" /> is what EU4 writes.
/// </summary>
public Encoding Encoding { get; }
@@ -28,21 +35,23 @@ public class SaveParserEU4
/// Uncompressed stream of <c>gamestate</c> file which can be extracted from save archive
/// </param>
/// <param name="query">
/// Parsing whole save takes 10 seconds on mid pc and takes 1GB of RAM,
/// Parsing whole save may take a few seconds on mid pc and takes 1GB of RAM,
/// so you should specify what exactly you want to get from save file
/// </param>
/// <param name="encoding">Encoding of the strings inside the save. Latin1 by default.</param>
/// <param name="encoding">Encoding of the strings inside the save. <see cref="DefaultEncoding"/></param>
/// <param name="bufferSize">Size of the read buffer. Mostly useful for tests.</param>
public SaveParserEU4(Stream savefile, ISearchExpression? query,
public SaveParserEU4(Stream savefile, SearchExpressionCompilation? query,
Encoding? encoding = null, int bufferSize = DefaultBufferSize)
{
Encoding = encoding ?? Encoding.Latin1;
_searchExprCurrent = query;
Encoding = encoding ?? DefaultEncoding;
_query = query;
_tokens = new Tokenizer(savefile, bufferSize);
}
public Dictionary<string, object> Parse()
{
// compiled here, so the keys of the query are always encoded like the save
_searchExprCurrent = _query?.Compile(Encoding);
_tokens.ReadHeader(Header, Encoding);
return ParseDict();
}
@@ -194,7 +203,7 @@ public class SaveParserEU4
ISearchExpression? searchExprNext = null;
bool matches = _searchExprCurrent == null
|| _searchExprCurrent.DoesMatch(
new MatchCandidate(localIndex, _tokens.Text, Encoding), out searchExprNext);
new MatchCandidate(localIndex, _tokens.Text), out searchExprNext);
string? keyStr = matches ? DecodeString(_tokens.Text) : null;
// next token should be `=` or `{`