From 0958ba20ee664a5fb47c60c61d22531e51dfa548 Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Sat, 28 Jun 2025 22:38:09 +0300 Subject: [PATCH] Reinclude tools --- Example.Shared/Example.Shared.csproj | 6 +- mROA.Codegen/Tools/DefineTemplateSection.cs | 30 +++++++ mROA.Codegen/Tools/ITemplateSection.cs | 20 +++++ mROA.Codegen/Tools/InnerTemplateSection.cs | 24 ++++++ mROA.Codegen/Tools/InsertTemplateSection.cs | 86 +++++++++++++++++++ mROA.Codegen/Tools/LinkTemplateSection.cs | 39 +++++++++ mROA.Codegen/Tools/LiteralTemplateSection.cs | 31 +++++++ mROA.Codegen/Tools/ProgrammableTextSection.cs | 29 +++++++ .../Tools/Reading/DefineSectionReader.cs | 24 ++++++ mROA.Codegen/Tools/Reading/ISectionReader.cs | 9 ++ .../Reading/InnerTemplateSectionReader.cs | 39 +++++++++ .../Tools/Reading/InsertSectionReader.cs | 24 ++++++ .../Tools/Reading/LeadingTextSectionReader.cs | 40 +++++++++ .../Tools/Reading/LinkSectionReader.cs | 20 +++++ mROA.Codegen/Tools/Reading/TemplateReader.cs | 82 ++++++++++++++++++ mROA.Codegen/Tools/TemplateDocument.cs | 61 +++++++++++++ mROA.Codegen/mROA.Codegen.csproj | 1 - 17 files changed, 563 insertions(+), 2 deletions(-) create mode 100644 mROA.Codegen/Tools/DefineTemplateSection.cs create mode 100644 mROA.Codegen/Tools/ITemplateSection.cs create mode 100644 mROA.Codegen/Tools/InnerTemplateSection.cs create mode 100644 mROA.Codegen/Tools/InsertTemplateSection.cs create mode 100644 mROA.Codegen/Tools/LinkTemplateSection.cs create mode 100644 mROA.Codegen/Tools/LiteralTemplateSection.cs create mode 100644 mROA.Codegen/Tools/ProgrammableTextSection.cs create mode 100644 mROA.Codegen/Tools/Reading/DefineSectionReader.cs create mode 100644 mROA.Codegen/Tools/Reading/ISectionReader.cs create mode 100644 mROA.Codegen/Tools/Reading/InnerTemplateSectionReader.cs create mode 100644 mROA.Codegen/Tools/Reading/InsertSectionReader.cs create mode 100644 mROA.Codegen/Tools/Reading/LeadingTextSectionReader.cs create mode 100644 mROA.Codegen/Tools/Reading/LinkSectionReader.cs create mode 100644 mROA.Codegen/Tools/Reading/TemplateReader.cs create mode 100644 mROA.Codegen/Tools/TemplateDocument.cs diff --git a/Example.Shared/Example.Shared.csproj b/Example.Shared/Example.Shared.csproj index 40a196f..f727333 100644 --- a/Example.Shared/Example.Shared.csproj +++ b/Example.Shared/Example.Shared.csproj @@ -7,10 +7,14 @@ - + + + + + diff --git a/mROA.Codegen/Tools/DefineTemplateSection.cs b/mROA.Codegen/Tools/DefineTemplateSection.cs new file mode 100644 index 0000000..31eadb7 --- /dev/null +++ b/mROA.Codegen/Tools/DefineTemplateSection.cs @@ -0,0 +1,30 @@ +namespace mROA.CodegenTools +{ + public class DefineTemplateSection : ITagged + { + public DefineTemplateSection(string storedText, string tag, TemplateDocument context) + { + StoredText = storedText; + Tag = tag; + Context = context; + } + + public string StoredText { get; } + public TemplateDocument Context { get; set; } + + public string Tag { get; } + + public int TargetLength => StoredText.Length; + + public object Clone() + { + return new DefineTemplateSection(StoredText, Tag, Context); + } + + + public override string ToString() + { + return StoredText; + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/ITemplateSection.cs b/mROA.Codegen/Tools/ITemplateSection.cs new file mode 100644 index 0000000..cf7d34c --- /dev/null +++ b/mROA.Codegen/Tools/ITemplateSection.cs @@ -0,0 +1,20 @@ +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; } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/InnerTemplateSection.cs b/mROA.Codegen/Tools/InnerTemplateSection.cs new file mode 100644 index 0000000..1a6d5f7 --- /dev/null +++ b/mROA.Codegen/Tools/InnerTemplateSection.cs @@ -0,0 +1,24 @@ +namespace mROA.CodegenTools +{ + public class InnerTemplateSection : ITemplateSection, ITagged + { + public InnerTemplateSection(string tag, TemplateDocument innerTemplate, TemplateDocument context) + { + Tag = tag; + Context = context; + InnerTemplate = innerTemplate; + } + + public TemplateDocument InnerTemplate { get; } + + public string Tag { get; } + + public TemplateDocument Context { get; set; } + public int TargetLength => 0; + + public object Clone() + { + return new InnerTemplateSection(Tag, InnerTemplate, Context); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/InsertTemplateSection.cs b/mROA.Codegen/Tools/InsertTemplateSection.cs new file mode 100644 index 0000000..e47cd50 --- /dev/null +++ b/mROA.Codegen/Tools/InsertTemplateSection.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using System.Linq; + +namespace mROA.CodegenTools +{ + public class InsertTemplateSection : ITagged, IBaking + { + public readonly List Parameters; + private object _insertedValue; + + public InsertTemplateSection(string tag, TemplateDocument context, params string[] parameters) + { + Tag = tag; + Parameters = parameters.ToList(); + Context = context; + } + + public string Bake() + { + switch (_insertedValue) + { + case null: + return string.Empty; + case string s: + return s; + default: + return ((ITemplateSection)_insertedValue).ToString(); + } + } + + public string Tag { get; private set; } + + public TemplateDocument Context { get; set; } + + + public int TargetLength => 0; + + public object Clone() + { + return new InsertTemplateSection(Tag, Context, Parameters.ToArray()); + } + + 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 = (InsertTemplateSection)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; + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/LinkTemplateSection.cs b/mROA.Codegen/Tools/LinkTemplateSection.cs new file mode 100644 index 0000000..45f58c6 --- /dev/null +++ b/mROA.Codegen/Tools/LinkTemplateSection.cs @@ -0,0 +1,39 @@ +namespace mROA.CodegenTools +{ + public class LinkTemplateSection : ITemplateSection, IBaking + { + public LinkTemplateSection(string linkedTag, TemplateDocument context) + { + LinkedTag = linkedTag; + Context = context; + } + + public string LinkedTag { get; } + + public string Bake() + { + return Context[LinkedTag]?.ToString(); + } + + public TemplateDocument Context { get; set; } + + public int TargetLength + { + get + { + var attached = Context[LinkedTag]; + return attached?.TargetLength ?? 0; + } + } + + public object Clone() + { + return new LinkTemplateSection(LinkedTag, Context); + } + + public override string ToString() + { + return $"{nameof(LinkedTag)}: {LinkedTag}"; + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/LiteralTemplateSection.cs b/mROA.Codegen/Tools/LiteralTemplateSection.cs new file mode 100644 index 0000000..45c2dec --- /dev/null +++ b/mROA.Codegen/Tools/LiteralTemplateSection.cs @@ -0,0 +1,31 @@ +namespace mROA.CodegenTools +{ + public class LiteralTemplateSection : ITemplateSection, IBaking + { + private readonly string _internalText; + + public LiteralTemplateSection(string internalText, TemplateDocument context) + { + _internalText = internalText; + Context = context; + } + + public string Bake() + { + return ToString(); + } + + public TemplateDocument Context { get; set; } + public int TargetLength => _internalText.Length; + + public object Clone() + { + return new LiteralTemplateSection(_internalText, Context); + } + + public override string ToString() + { + return _internalText; + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/ProgrammableTextSection.cs b/mROA.Codegen/Tools/ProgrammableTextSection.cs new file mode 100644 index 0000000..0e34391 --- /dev/null +++ b/mROA.Codegen/Tools/ProgrammableTextSection.cs @@ -0,0 +1,29 @@ +using System; + +namespace mROA.CodegenTools +{ + public class ProgrammableTextSection : ITemplateSection, IBaking + { + private readonly Func _bakeFunc; + + public ProgrammableTextSection(Func bakeFunc, TemplateDocument context) + { + _bakeFunc = bakeFunc; + Context = context; + } + + + public string Bake() + { + return _bakeFunc(Context.AdditionalContext); + } + + public TemplateDocument Context { get; set; } + public int TargetLength => 0; + + public object Clone() + { + return new ProgrammableTextSection(_bakeFunc, Context); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/Reading/DefineSectionReader.cs b/mROA.Codegen/Tools/Reading/DefineSectionReader.cs new file mode 100644 index 0000000..0f3840a --- /dev/null +++ b/mROA.Codegen/Tools/Reading/DefineSectionReader.cs @@ -0,0 +1,24 @@ +using System; + +namespace mROA.CodegenTools.Reading +{ + public class DefineSectionReader : LeadingTextSectionReader + { + public DefineSectionReader() : base("", index, StringComparison.Ordinal); + var sectionName = GetTagValue(index, tagEnd); + tagEnd += 1; + var endIndex = TemplateText.IndexOf("", tagEnd, StringComparison.Ordinal); + var storedText = TemplateText.Substring(tagEnd, endIndex - tagEnd); + index = endIndex + 4; + PassCaretToCloseSymbol(); + PassCaretToCloseSymbol(); + return new DefineTemplateSection(storedText, sectionName, document); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/Reading/ISectionReader.cs b/mROA.Codegen/Tools/Reading/ISectionReader.cs new file mode 100644 index 0000000..fd89e5d --- /dev/null +++ b/mROA.Codegen/Tools/Reading/ISectionReader.cs @@ -0,0 +1,9 @@ +namespace mROA.CodegenTools.Reading +{ + public interface ISectionReader + { + string TemplateText { get; set; } + int GetNextSectionIndex(int currentIndex); + ITemplateSection ExtractSection(ref int index, TemplateDocument document); + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/Reading/InnerTemplateSectionReader.cs b/mROA.Codegen/Tools/Reading/InnerTemplateSectionReader.cs new file mode 100644 index 0000000..11fc269 --- /dev/null +++ b/mROA.Codegen/Tools/Reading/InnerTemplateSectionReader.cs @@ -0,0 +1,39 @@ +using System; + +namespace mROA.CodegenTools.Reading +{ + public class InnerTemplateSectionReader : LeadingTextSectionReader + { + public InnerTemplateSectionReader() + : base("", start, StringComparison.Ordinal); + var innerStartSymbol = TemplateText.IndexOf("", _currentCaretPosition, StringComparison.Ordinal) + 1; + return _currentCaretPosition; + } + + protected string GetTagValue(int from, int to) + { + var realStart = from + 4; + var span = TemplateText.Substring(realStart, to - realStart); + return span; + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/Reading/LinkSectionReader.cs b/mROA.Codegen/Tools/Reading/LinkSectionReader.cs new file mode 100644 index 0000000..07947ad --- /dev/null +++ b/mROA.Codegen/Tools/Reading/LinkSectionReader.cs @@ -0,0 +1,20 @@ +namespace mROA.CodegenTools.Reading +{ + public class LinkSectionReader : LeadingTextSectionReader + { + public LinkSectionReader() : base(" ReaderTypes = new() + { + typeof(DefineSectionReader), + typeof(InsertSectionReader), + typeof(LinkSectionReader), + typeof(InnerTemplateSectionReader) + }; + + public static TemplateDocument Parse(string templateText) + { + var currentIndex = 0; + var activeReaders = new List(); + + 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(); + var 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); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/Tools/TemplateDocument.cs b/mROA.Codegen/Tools/TemplateDocument.cs new file mode 100644 index 0000000..cfaac8f --- /dev/null +++ b/mROA.Codegen/Tools/TemplateDocument.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace mROA.CodegenTools +{ + public class TemplateDocument : ICloneable + { + public List Parts { get; set; } = new(); + public object AdditionalContext { get; set; } + public ITagged? this[string tag] => Parts.OfType().FirstOrDefault(i => i.Tag == tag); + + 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 Insert(string tag, object value) + { + var selectedPart = this[tag]; + if (selectedPart is InsertTemplateSection 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()) + { + var baked = part.Bake(); + stringBuilder.Append(baked); + } + + return stringBuilder.ToString(); + } + + public void AddDefine(string tag, string text) + { + Parts.Add(new DefineTemplateSection(text, tag, this)); + } + + public void AddDefine(string tag, object value) + { + AddDefine(tag, value.ToString()); + } + } +} \ No newline at end of file diff --git a/mROA.Codegen/mROA.Codegen.csproj b/mROA.Codegen/mROA.Codegen.csproj index 64525f2..7fa5e54 100644 --- a/mROA.Codegen/mROA.Codegen.csproj +++ b/mROA.Codegen/mROA.Codegen.csproj @@ -26,7 +26,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive -