128 lines
5.2 KiB
C#
128 lines
5.2 KiB
C#
namespace RolemasterDb.CriticalParsing;
|
|
|
|
public static class CriticalCellTextParser
|
|
{
|
|
public static CriticalCellParseContent Parse(string rawCellText, AffixLegend affixLegend)
|
|
{
|
|
var lines = rawCellText
|
|
.Split(["\r\n", "\n", "\r"], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
|
.ToList();
|
|
return Parse(lines, affixLegend);
|
|
}
|
|
|
|
public static CriticalCellParseContent Parse(IReadOnlyList<string> lines, AffixLegend affixLegend)
|
|
{
|
|
var validationErrors = new List<string>();
|
|
var branchStartIndexes = FindBranchStartIndexes(lines);
|
|
var baseLineCount = branchStartIndexes.Count == 0 ? lines.Count : branchStartIndexes[0];
|
|
var baseLines = lines.Take(baseLineCount).ToList();
|
|
var branches = new List<ParsedCriticalBranch>();
|
|
var affixLegendSymbols = affixLegend.ClassificationSymbols;
|
|
|
|
validationErrors.AddRange(ValidateSegmentCount(baseLines, affixLegendSymbols, "Base content"));
|
|
|
|
for (var branchIndex = 0; branchIndex < branchStartIndexes.Count; branchIndex++)
|
|
{
|
|
var startIndex = branchStartIndexes[branchIndex];
|
|
var endIndex = branchIndex == branchStartIndexes.Count - 1
|
|
? lines.Count
|
|
: branchStartIndexes[branchIndex + 1];
|
|
|
|
branches.Add(ParseBranch(
|
|
lines.Skip(startIndex).Take(endIndex - startIndex).ToList(),
|
|
branchIndex + 1,
|
|
affixLegend,
|
|
validationErrors));
|
|
}
|
|
|
|
var (rawText, descriptionText, rawAffixText) = BuildTextSections(baseLines, affixLegendSymbols);
|
|
var effects = AffixEffectParser.Parse(rawAffixText, affixLegend);
|
|
return new CriticalCellParseContent(baseLines, rawText, descriptionText, rawAffixText, effects, branches, validationErrors);
|
|
}
|
|
|
|
private static ParsedCriticalBranch ParseBranch(
|
|
IReadOnlyList<string> branchLines,
|
|
int sortOrder,
|
|
AffixLegend affixLegend,
|
|
List<string> validationErrors)
|
|
{
|
|
var firstLine = branchLines[0];
|
|
var separatorIndex = firstLine.IndexOf(':', StringComparison.Ordinal);
|
|
var conditionText = CriticalCellParserSupport.CollapseWhitespace(firstLine[..separatorIndex]);
|
|
var firstPayloadLine = CriticalCellParserSupport.CollapseWhitespace(firstLine[(separatorIndex + 1)..]);
|
|
var payloadLines = new List<string>();
|
|
|
|
if (!string.IsNullOrWhiteSpace(firstPayloadLine))
|
|
{
|
|
payloadLines.Add(firstPayloadLine);
|
|
}
|
|
|
|
foreach (var continuationLine in branchLines.Skip(1))
|
|
{
|
|
var normalized = CriticalCellParserSupport.CollapseWhitespace(continuationLine);
|
|
if (!string.IsNullOrWhiteSpace(normalized))
|
|
{
|
|
payloadLines.Add(normalized);
|
|
}
|
|
}
|
|
|
|
var affixLegendSymbols = affixLegend.ClassificationSymbols;
|
|
validationErrors.AddRange(ValidateSegmentCount(payloadLines, affixLegendSymbols, $"Branch '{conditionText}'"));
|
|
|
|
var (_, descriptionText, rawAffixText) = BuildTextSections(payloadLines, affixLegendSymbols);
|
|
var effects = AffixEffectParser.Parse(rawAffixText, affixLegend);
|
|
return new ParsedCriticalBranch(
|
|
"conditional",
|
|
CriticalCellParserSupport.NormalizeConditionKey(conditionText),
|
|
conditionText,
|
|
string.Join(Environment.NewLine, branchLines),
|
|
descriptionText,
|
|
rawAffixText,
|
|
effects,
|
|
sortOrder);
|
|
}
|
|
|
|
private static List<int> FindBranchStartIndexes(IReadOnlyList<string> lines)
|
|
{
|
|
var branchStartIndexes = new List<int>();
|
|
|
|
for (var index = 0; index < lines.Count; index++)
|
|
{
|
|
if (CriticalCellParserSupport.IsConditionalBranchStartLine(lines[index]))
|
|
{
|
|
branchStartIndexes.Add(index);
|
|
}
|
|
}
|
|
|
|
return branchStartIndexes;
|
|
}
|
|
|
|
private static IReadOnlyList<string> ValidateSegmentCount(
|
|
IReadOnlyList<string> lines,
|
|
IReadOnlySet<string> affixLegendSymbols,
|
|
string scope)
|
|
{
|
|
if (lines.Count == 0)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
var segmentCount = CriticalCellParserSupport.CountLineTypeSegments(lines, affixLegendSymbols);
|
|
return segmentCount > 2
|
|
? [$"{scope} interleaves prose and affix lines."]
|
|
: [];
|
|
}
|
|
|
|
private static (string RawText, string DescriptionText, string? RawAffixText) BuildTextSections(
|
|
IReadOnlyList<string> lines,
|
|
IReadOnlySet<string> affixLegendSymbols)
|
|
{
|
|
var rawText = string.Join(Environment.NewLine, lines);
|
|
var rawAffixLines = lines.Where(line => CriticalCellParserSupport.IsAffixLikeLine(line, affixLegendSymbols)).ToList();
|
|
var descriptionLines = lines.Where(line => !CriticalCellParserSupport.IsAffixLikeLine(line, affixLegendSymbols)).ToList();
|
|
var descriptionText = CriticalCellParserSupport.CollapseWhitespace(string.Join(' ', descriptionLines));
|
|
var rawAffixText = rawAffixLines.Count == 0 ? null : string.Join(Environment.NewLine, rawAffixLines);
|
|
return (rawText, descriptionText, rawAffixText);
|
|
}
|
|
}
|