Успешно переписаны не полностью два файла

This commit is contained in:
2025-03-25 21:27:54 +03:00
parent 155d942a03
commit bf636c0f9c
23 changed files with 676 additions and 98 deletions
@@ -0,0 +1,32 @@
using System;
namespace mROA.CodegenTools
{
public class DefineTemplateSection : ITagged
{
public TemplateDocument Context { get; set; }
public string StoredText { get; }
private readonly string _tag;
public DefineTemplateSection(string storedText, string tag, TemplateDocument context)
{
StoredText = storedText;
_tag = tag;
Context = context;
}
public string Tag => _tag;
public int TargetLength => StoredText.Length;
public override string ToString()
{
return StoredText;
}
public object Clone()
{
return new DefineTemplateSection(StoredText, _tag, Context);
}
}
}
+21
View File
@@ -0,0 +1,21 @@
using System;
namespace mROA.CodegenTools
{
public interface ITemplateSection : ICloneable
{
TemplateDocument Context { get; set; }
int TargetLength { get; }
}
public interface IBaking
{
string Bake();
}
public interface ITagged : ITemplateSection
{
string Tag { get; }
}
}
@@ -0,0 +1,25 @@
namespace mROA.CodegenTools
{
public class InnerTemplateSection : ITemplateSection, ITagged
{
private readonly string _tag;
public TemplateDocument Context { get; set; }
public int TargetLength => 0;
public string Tag => _tag;
public TemplateDocument InnerTemplate { get; }
public InnerTemplateSection(string tag, TemplateDocument innerTemplate, TemplateDocument context)
{
_tag = tag;
Context = context;
InnerTemplate = innerTemplate;
}
public object Clone()
{
return new InnerTemplateSection(_tag, InnerTemplate, Context);
}
}
}
+86
View File
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace mROA.CodegenTools
{
public class InsertTemplatePart : ITagged, IBaking
{
private object _insertedValue;
private string _tag;
public string Tag => _tag;
public TemplateDocument Context { get; set; }
public readonly List<string> Parameters;
public InsertTemplatePart(string tag, TemplateDocument context, params string[] parameters)
{
_tag = tag;
Parameters = parameters.ToList();
Context = context;
}
private bool IsInserted(object value)
{
if (Parameters.IndexOf("r") == -1) return false;
ProduceInserted(value);
return true;
}
private void ProduceInserted(object value)
{
var currentIndex = Context.Parts.IndexOf(this);
var clone = (InsertTemplatePart)MemberwiseClone();
clone._tag += "+";
clone._insertedValue = value;
Context.Parts.Insert(currentIndex, clone);
InsertSeparator(currentIndex + 1);
}
private void InsertSeparator(int currentIndex)
{
var sepIndex = Parameters.IndexOf("sep");
if (sepIndex == -1)
return;
Context.Parts.Insert(currentIndex, new LiteralTemplateSection(Context[Parameters[sepIndex + 1]].ToString(), Context));
}
public void Setup(object value)
{
if (!(value is string) && !(value is ITemplateSection) )
return;
if (IsInserted(value))
return;
_insertedValue = value;
}
public int TargetLength => 0;
public string Bake()
{
switch (_insertedValue)
{
case null:
return string.Empty;
case string s:
return s;
default:
return ((ITemplateSection)_insertedValue).ToString();
}
}
public object Clone()
{
return new InsertTemplatePart(_tag, Context, Parameters.ToArray());
}
}
}
+43
View File
@@ -0,0 +1,43 @@
using System.Linq;
namespace mROA.CodegenTools
{
public class LinkTemplateSection : ITemplateSection, IBaking
{
private readonly string _linkedTag;
public LinkTemplateSection(string linkedTag, TemplateDocument context)
{
_linkedTag = linkedTag;
Context = context;
}
public TemplateDocument Context { get; set; }
public string LinkedTag => _linkedTag;
public int TargetLength
{
get
{
var attached = Context[_linkedTag];
return attached?.TargetLength ?? 0;
}
}
public string Bake()
{
return Context[_linkedTag]?.ToString();
}
public override string ToString()
{
return $"{nameof(LinkedTag)}: {_linkedTag}";
}
public object Clone()
{
return new LinkTemplateSection(_linkedTag, Context);
}
}
}
@@ -0,0 +1,31 @@
namespace mROA.CodegenTools
{
public class LiteralTemplateSection : ITemplateSection, IBaking
{
private string _internalText;
public LiteralTemplateSection(string internalText, TemplateDocument context)
{
_internalText = internalText;
Context = context;
}
public TemplateDocument Context { get; set; }
public int TargetLength => _internalText.Length;
public string Bake()
{
return ToString();
}
public override string ToString()
{
return _internalText;
}
public object Clone()
{
return new LiteralTemplateSection(_internalText, Context);
}
}
}
@@ -0,0 +1,29 @@
using System;
namespace mROA.CodegenTools
{
public class ProgrammableTextSection : ITemplateSection, IBaking
{
public TemplateDocument Context { get; set; }
public int TargetLength => 0;
private Func<object, string> _bakeFunc;
public ProgrammableTextSection(Func<object, string> bakeFunc, TemplateDocument context)
{
_bakeFunc = bakeFunc;
Context = context;
}
public string Bake()
{
return _bakeFunc(Context.AdditionalContext);
}
public object Clone()
{
return new ProgrammableTextSection(_bakeFunc, Context);
}
}
}
@@ -0,0 +1,24 @@
using System;
namespace mROA.CodegenTools
{
public class DefineSectionReader : LeadingTextSectionReader
{
public DefineSectionReader() : base("<!D")
{
}
public override ITemplateSection ExtractSection(ref int index, TemplateDocument document)
{
var tagEnd = TemplateText.IndexOf(">", index, StringComparison.Ordinal);
var sectionName = GetTagValue(index, tagEnd);
tagEnd += 1;
var endIndex = TemplateText.IndexOf("<!D>", tagEnd, StringComparison.Ordinal);
var storedText = TemplateText.Substring(tagEnd, endIndex - tagEnd);
index = endIndex + 4;
PassCaretToCloseSymbol();
PassCaretToCloseSymbol();
return new DefineTemplateSection(storedText, sectionName, document);
}
}
}
@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace mROA.CodegenTools
{
public interface ISectionReader
{
string TemplateText { get; set; }
int GetNextSectionIndex(int currentIndex);
ITemplateSection ExtractSection(ref int index, TemplateDocument document);
}
}
@@ -0,0 +1,39 @@
using System;
namespace mROA.CodegenTools
{
public class InnerTemplateSectionReader : LeadingTextSectionReader
{
public InnerTemplateSectionReader()
: base("<!T")
{
}
public override ITemplateSection ExtractSection(ref int index, TemplateDocument document)
{
var end = FindEnd(index + 4);
var from = index;
index = PassCaretToCloseSymbol();
var to = index - 1;
var tagName = GetTagValue(from, to);
var innerDocText = TemplateText.Substring(index, end - index);
var innerDoc = TemplateReader.Parse(innerDocText);
_currentCaretPosition = end + 4;
index = _currentCaretPosition;
return new InnerTemplateSection(tagName, innerDoc, document);
}
private int FindEnd(int start)
{
var endSymbol = TemplateText.IndexOf("<!T>", start, StringComparison.Ordinal);
var innerStartSymbol = TemplateText.IndexOf("<!T ", start, StringComparison.Ordinal);
if (endSymbol < innerStartSymbol || innerStartSymbol == -1)
return endSymbol;
return FindEnd(endSymbol + 4);
}
}
}
@@ -0,0 +1,24 @@
using System.Linq;
namespace mROA.CodegenTools
{
public class InsertSectionReader : LeadingTextSectionReader
{
public InsertSectionReader() : base("<!I")
{
}
public override ITemplateSection ExtractSection(ref int index, TemplateDocument document)
{
var from = index;
index = PassCaretToCloseSymbol();
var to = index - 1;
var tagText = GetTagValue(from, to);
var parts = tagText.Split(' ');
return new InsertTemplatePart(parts[0], document, parts.Skip(1).ToArray());
}
}
}
@@ -0,0 +1,41 @@
using System;
namespace mROA.CodegenTools
{
public abstract class LeadingTextSectionReader : ISectionReader
{
protected int _currentCaretPosition;
private string _tagLeading;
protected LeadingTextSectionReader(string tagLeading)
{
_tagLeading = tagLeading + " ";
}
protected int PassCaretToCloseSymbol()
{
_currentCaretPosition = TemplateText.IndexOf(">", _currentCaretPosition, StringComparison.Ordinal) + 1;
return _currentCaretPosition;
}
public string TemplateText { get; set; }
public int GetNextSectionIndex(int currentIndex)
{
_currentCaretPosition = Math.Max(currentIndex, _currentCaretPosition);
var index = TemplateText.IndexOf(_tagLeading, _currentCaretPosition, StringComparison.Ordinal);
_currentCaretPosition = index;
return index;
}
public abstract ITemplateSection ExtractSection(ref int index, TemplateDocument document);
protected string GetTagValue(int from, int to)
{
var realStart = from + 4;
var span = TemplateText.AsSpan();
var slice = span.Slice(realStart, to - realStart);
return new string(slice.ToArray());
}
}
}
@@ -0,0 +1,20 @@
namespace mROA.CodegenTools
{
public class LinkSectionReader : LeadingTextSectionReader
{
public LinkSectionReader() : base("<!L")
{
}
public override ITemplateSection ExtractSection(ref int index, TemplateDocument document)
{
var from = index;
index = PassCaretToCloseSymbol();
var to = index - 1;
var tagText = GetTagValue(from, to);
return new LinkTemplateSection(tagText, document);
}
}
}
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace mROA.CodegenTools
{
public static class TemplateReader
{
private static readonly List<Type> ReaderTypes = new List<Type>
{
typeof(DefineSectionReader),
typeof(InsertSectionReader),
typeof(LinkSectionReader),
typeof(InnerTemplateSectionReader)
};
public static TemplateDocument Parse(string templateText)
{
int currentIndex = 0;
var activeReaders = new List<ISectionReader>();
foreach (var readerType in ReaderTypes)
{
var reader = Activator.CreateInstance(readerType) as ISectionReader;
reader.TemplateText = templateText;
activeReaders.Add(reader);
}
var doc = new TemplateDocument();
while (currentIndex < templateText.Length)
{
List<(ISectionReader reader, int index)> indices = activeReaders.Select(i => ((ISectionReader Readers, int index))(i, i.GetNextSectionIndex(currentIndex))).Where(i => i.index > -1).ToList();
int minIndex = templateText.Length;
ISectionReader minReader = null;
if (indices.Count != 0)
{
minIndex = indices.Min(i => i.index);
minReader = indices.FirstOrDefault(i => i.index == minIndex).reader;
if (indices.Count != activeReaders.Count)
{
activeReaders = indices.Select(i => i.reader).ToList();
}
}
if (currentIndex != minIndex)
{
var literalText = templateText.Substring(currentIndex, minIndex - currentIndex);
var literal =
new LiteralTemplateSection(literalText, doc);
doc.Parts.Add(literal);
currentIndex = minIndex;
}
if (indices.Count != 0)
{
var section = minReader.ExtractSection(ref currentIndex, doc);
doc.Parts.Add(section);
}
}
return doc;
}
public static TemplateDocument FromEmbeddedResource(string resourceName)
{
return FromEmbeddedResource(resourceName, Assembly.GetCallingAssembly());
}
public static TemplateDocument FromEmbeddedResource(string resourceName, Assembly assembly)
{
var fileName = assembly.GetManifestResourceNames().First(n => n.EndsWith(resourceName));
var res = assembly.GetManifestResourceStream(fileName);
var reader = new StreamReader(res);
var templateText = reader.ReadToEnd();
return Parse(templateText);
}
}
}
+59
View File
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace mROA.CodegenTools
{
public class TemplateDocument : ICloneable
{
public List<ITemplateSection> Parts { get; set; } = new List<ITemplateSection>();
public object AdditionalContext { get; set; }
public ITagged this[string tag] => Parts.OfType<ITagged>().FirstOrDefault(i => i.Tag == tag);
public void Insert(string tag, object value)
{
var selectedPart = this[tag];
if (selectedPart is InsertTemplatePart itp)
{
itp.Setup(value);
}
}
public string Compile()
{
var approximatelyLength = Parts.Sum(i => i.TargetLength);
var stringBuilder = new StringBuilder(approximatelyLength);
foreach (var part in Parts.OfType<IBaking>())
{
var baked = part.Bake();
stringBuilder.Append(baked);
}
return stringBuilder.ToString();
}
public object Clone()
{
var cloneDoc = new TemplateDocument
{
AdditionalContext = AdditionalContext is ICloneable c ? c.Clone() : AdditionalContext
};
cloneDoc.Parts = Parts.Select(i =>
{
var clone = i.Clone() as ITemplateSection;
clone.Context = cloneDoc;
return clone;
}).ToList();
return cloneDoc;
}
public void AddDefine(string tag, string text)
{
Parts.Add(new DefineTemplateSection(text, tag, this));
}
}
}