Парсер шаблонов готов

This commit is contained in:
2025-03-23 19:32:41 +03:00
parent e93a028bc4
commit b58bddc1a3
19 changed files with 352 additions and 22 deletions
+20
View File
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\mROA.CodegenTools\mROA.CodegenTools.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="exampleTemplate.cstmpl">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
+23
View File
@@ -0,0 +1,23 @@
// See https://aka.ms/new-console-template for more information
using mROA.CodegenTools;
// var doc = new TemplateDocument();
// doc.Parts = new List<ITemplateSection>
// {
// new LiteralTemplateSection("teset text", doc),
// new DefineTemplateSection(" another text which is dinided, bun not placed ", "text define", doc),
// new LinkTemplateSection("text define", doc),
// new LinkTemplateSection("text define", doc),
// new LinkTemplateSection("text define", doc),
// new LiteralTemplateSection(" = = = ", doc),
// new InsertTemplatePart("insert", doc),
// new LinkTemplateSection("post", doc)
// };
//
// doc.Insert("insert", "inserted text by insert template => ");
// doc.Parts.Add(new DefineTemplateSection("post added", "post", doc));
// Console.WriteLine(doc.Compile());
var doc = TemplateReader.Parce(File.ReadAllText("exampleTemplate.cstmpl"));
Console.WriteLine(doc.Parts.Count);
+19
View File
@@ -0,0 +1,19 @@
public class A
{
<!L linkTagA>
<!L linkTag>
<!L linkTag>
Some literal for test
<!D linkTagA>test text with definition in template<!D>
<!I ctorInserting>
<!I methodInserting R>
<!T MethodTemplate>
public void <!L methodName>()
{
Console.WriteLine("<!L printText>");
}
<!T>
}
+2 -6
View File
@@ -2,7 +2,7 @@ using System;
namespace mROA.CodegenTools namespace mROA.CodegenTools
{ {
public class DefineTemplateSection : ITemplateSection, ITagged public class DefineTemplateSection : ITagged
{ {
public TemplateDocument Context { get; set; } public TemplateDocument Context { get; set; }
public string StoredText { get; } public string StoredText { get; }
@@ -18,14 +18,10 @@ namespace mROA.CodegenTools
public string Tag => _tag; public string Tag => _tag;
public int TargetLength => StoredText.Length; public int TargetLength => StoredText.Length;
public string Bake()
{
return String.Empty;
}
public override string ToString() public override string ToString()
{ {
return StoredText; return $"{nameof(_tag)}: {_tag}, {nameof(StoredText)}: {StoredText}";
} }
} }
} }
+6 -1
View File
@@ -4,9 +4,14 @@ namespace mROA.CodegenTools
{ {
TemplateDocument Context { get; set; } TemplateDocument Context { get; set; }
int TargetLength { get; } int TargetLength { get; }
string Bake();
} }
public interface IBaking
{
string Bake();
}
public interface ITagged : ITemplateSection public interface ITagged : ITemplateSection
{ {
string Tag { get; } string Tag { get; }
+20
View File
@@ -0,0 +1,20 @@
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;
}
}
}
+5 -4
View File
@@ -1,9 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
namespace mROA.CodegenTools namespace mROA.CodegenTools
{ {
public class InsertTemplatePart : ITagged public class InsertTemplatePart : ITagged, IBaking
{ {
private object _insertedValue; private object _insertedValue;
private string _tag; private string _tag;
@@ -11,10 +12,10 @@ namespace mROA.CodegenTools
public TemplateDocument Context { get; set; } public TemplateDocument Context { get; set; }
public readonly List<string> Parameters; public readonly List<string> Parameters;
public InsertTemplatePart(string tag, List<string> parameters, TemplateDocument context) public InsertTemplatePart(string tag, TemplateDocument context, params string[] parameters)
{ {
_tag = tag; _tag = tag;
Parameters = parameters; Parameters = parameters.ToList();
Context = context; Context = context;
} }
@@ -61,7 +62,7 @@ namespace mROA.CodegenTools
case string s: case string s:
return s; return s;
default: default:
return ((ITemplateSection)_insertedValue).Bake(); return ((ITemplateSection)_insertedValue).ToString();
} }
} }
} }
+15 -3
View File
@@ -2,7 +2,7 @@ using System.Linq;
namespace mROA.CodegenTools namespace mROA.CodegenTools
{ {
public class LinkTemplateSection : ITemplateSection public class LinkTemplateSection : ITemplateSection, IBaking
{ {
private readonly string _linkedTag; private readonly string _linkedTag;
@@ -16,11 +16,23 @@ namespace mROA.CodegenTools
public string LinkedTag => _linkedTag; public string LinkedTag => _linkedTag;
public int TargetLength { get; } public int TargetLength
{
get
{
var attached = Context[_linkedTag];
return attached?.TargetLength ?? 0;
}
}
public string Bake() public string Bake()
{ {
return Context[_linkedTag]?.Bake(); return Context[_linkedTag]?.ToString();
}
public override string ToString()
{
return $"{nameof(LinkedTag)}: {_linkedTag}";
} }
} }
} }
+3 -3
View File
@@ -1,6 +1,6 @@
namespace mROA.CodegenTools namespace mROA.CodegenTools
{ {
public class LiteralTemplateSection : ITemplateSection public class LiteralTemplateSection : ITemplateSection, IBaking
{ {
private string _internalText; private string _internalText;
@@ -11,11 +11,11 @@ namespace mROA.CodegenTools
} }
public TemplateDocument Context { get; set; } public TemplateDocument Context { get; set; }
public int TargetLength { get; } public int TargetLength => _internalText.Length;
public string Bake() public string Bake()
{ {
return _internalText; return ToString();
} }
public override string ToString() public override string ToString()
+1 -1
View File
@@ -2,7 +2,7 @@ using System;
namespace mROA.CodegenTools namespace mROA.CodegenTools
{ {
public class ProgrammableTextSection : ITemplateSection public class ProgrammableTextSection : ITemplateSection, IBaking
{ {
public TemplateDocument Context { get; set; } public TemplateDocument Context { get; set; }
public int TargetLength => 0; public int TargetLength => 0;
@@ -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,38 @@
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;
var to = PassCaretToCloseSymbol();
index = to;
var tagName = GetTagValue(from, to);
var innerDocText = TemplateText.Substring(index, end - index);
var innerDoc = TemplateReader.Parce(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;
var to = PassCaretToCloseSymbol();
index = to;
var tagText = GetTagValue(from, to);
var parts = tagText.Split(' ');
return new InsertTemplatePart(parts[0], document, parts.Skip(1).ToArray());
}
}
}
@@ -0,0 +1,38 @@
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)
{
return TemplateText.Substring(from + 4, to - from - 5);
}
}
}
@@ -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;
var to = PassCaretToCloseSymbol();
index = to;
var tagText = GetTagValue(from, to);
return new LinkTemplateSection(tagText, document);
}
}
}
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
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 Parce(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;
}
}
}
+3 -4
View File
@@ -6,7 +6,7 @@ namespace mROA.CodegenTools
{ {
public class TemplateDocument public class TemplateDocument
{ {
public List<ITemplateSection> Parts { get; } public List<ITemplateSection> Parts { get; set; } = new List<ITemplateSection>();
public object AdditionalContext { get; set; } public object AdditionalContext { get; set; }
public ITagged this[string tag] => Parts.OfType<ITagged>().FirstOrDefault(i => i.Tag == tag); public ITagged this[string tag] => Parts.OfType<ITagged>().FirstOrDefault(i => i.Tag == tag);
public void Insert(string tag, object value) public void Insert(string tag, object value)
@@ -22,10 +22,9 @@ namespace mROA.CodegenTools
{ {
var approximatelyLength = Parts.Sum(i => i.TargetLength); var approximatelyLength = Parts.Sum(i => i.TargetLength);
var stringBuilder = new StringBuilder(approximatelyLength); var stringBuilder = new StringBuilder(approximatelyLength);
for (int i = 0; i < Parts.Count; i++) foreach (var part in Parts.OfType<IBaking>())
{ {
var part = Parts[i];
var baked = part.Bake(); var baked = part.Bake();
stringBuilder.Append(baked); stringBuilder.Append(baked);
} }
+10
View File
@@ -33,6 +33,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Events.Client", "Ex
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.CodegenTools", "mROA.CodegenTools\mROA.CodegenTools.csproj", "{2A2821B7-E5C5-443A-9801-9622493594A0}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.CodegenTools", "mROA.CodegenTools\mROA.CodegenTools.csproj", "{2A2821B7-E5C5-443A-9801-9622493594A0}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Codegen", "Codegen", "{3DB22457-E65B-426F-B3DD-08C615132B3E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicDemo", "BasicDemo\BasicDemo.csproj", "{87396E86-D7ED-4556-AB50-F3696FEF9072}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -87,6 +91,10 @@ Global
{2A2821B7-E5C5-443A-9801-9622493594A0}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A2821B7-E5C5-443A-9801-9622493594A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A2821B7-E5C5-443A-9801-9622493594A0}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A2821B7-E5C5-443A-9801-9622493594A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A2821B7-E5C5-443A-9801-9622493594A0}.Release|Any CPU.Build.0 = Release|Any CPU {2A2821B7-E5C5-443A-9801-9622493594A0}.Release|Any CPU.Build.0 = Release|Any CPU
{87396E86-D7ED-4556-AB50-F3696FEF9072}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{87396E86-D7ED-4556-AB50-F3696FEF9072}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87396E86-D7ED-4556-AB50-F3696FEF9072}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87396E86-D7ED-4556-AB50-F3696FEF9072}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -100,5 +108,7 @@ Global
{6342C7FC-12B4-4BC6-BA25-159B1400D952} = {032E1288-4D26-4FA5-ABB6-E7D738F319DE} {6342C7FC-12B4-4BC6-BA25-159B1400D952} = {032E1288-4D26-4FA5-ABB6-E7D738F319DE}
{B63F58B2-8D86-42F3-96A5-470CB449BFD3} = {032E1288-4D26-4FA5-ABB6-E7D738F319DE} {B63F58B2-8D86-42F3-96A5-470CB449BFD3} = {032E1288-4D26-4FA5-ABB6-E7D738F319DE}
{98451C0E-E179-4F5F-9F1A-8B353EDE2EBC} = {032E1288-4D26-4FA5-ABB6-E7D738F319DE} {98451C0E-E179-4F5F-9F1A-8B353EDE2EBC} = {032E1288-4D26-4FA5-ABB6-E7D738F319DE}
{3DB22457-E65B-426F-B3DD-08C615132B3E} = {EAE92F5A-664C-41AB-8811-5885524B5347}
{87396E86-D7ED-4556-AB50-F3696FEF9072} = {3DB22457-E65B-426F-B3DD-08C615132B3E}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal