Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Hypercube.Utilities.sln
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hypercube.Utilities.Analyze
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hypercube.Utilities.Analyzers.CodeFix", "src\Hypercube.Utilities.Analyzers.CodeFix\Hypercube.Utilities.Analyzers.CodeFix.csproj", "{33E0A347-BAE3-43A1-9D6B-E5AF033CCE16}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Main", "Main\Main.csproj", "{6BB9C8F4-4BA5-45EA-8924-1DE5771DF4BF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -30,5 +32,9 @@ Global
{33E0A347-BAE3-43A1-9D6B-E5AF033CCE16}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33E0A347-BAE3-43A1-9D6B-E5AF033CCE16}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33E0A347-BAE3-43A1-9D6B-E5AF033CCE16}.Release|Any CPU.Build.0 = Release|Any CPU
{6BB9C8F4-4BA5-45EA-8924-1DE5771DF4BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BB9C8F4-4BA5-45EA-8924-1DE5771DF4BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BB9C8F4-4BA5-45EA-8924-1DE5771DF4BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BB9C8F4-4BA5-45EA-8924-1DE5771DF4BF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
14 changes: 14 additions & 0 deletions Main/Main.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\src\Hypercube.Utilities\Hypercube.Utilities.csproj" />
</ItemGroup>

</Project>
13 changes: 13 additions & 0 deletions Main/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Hypercube.Utilities.Serialization.Hml;

namespace Main;

public static class Program
{
public static void Main()
{
var data = new { Name = "ТесмиДев", Age = 20, Da = new {}, Roles = new[] {"Programmer", "Driver"} };
//var data = new[] { new[] { "Programmer" }, new[] { "Programmer" }};
Console.WriteLine(HmlSerializer.Serialize(data, new HmlSerializerOptions() { WriteIndented = true }));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;

namespace Hypercube.Analyzers.CodeFix;
namespace Hypercube.Utilities.Analyzers.CodeFix;

[Shared, ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(DependencyCodeFixProvider))]
public sealed class DependencyCodeFixProvider : CodeFixProvider
Expand Down
2 changes: 1 addition & 1 deletion src/Hypercube.Utilities.Analyzers/DependencyAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Hypercube.Analyzers;
namespace Hypercube.Utilities.Analyzers;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class DependencyAnalyzer : DiagnosticAnalyzer
Expand Down
2 changes: 1 addition & 1 deletion src/Hypercube.Utilities.Analyzers/DependencySuppressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Hypercube.Analyzers;
namespace Hypercube.Utilities.Analyzers;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class DependencySuppressor : DiagnosticSuppressor
Expand Down
4 changes: 1 addition & 3 deletions src/Hypercube.Utilities/Helpers/ReflectionHelper.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System.Reflection;
using System.Xml.XPath;
using Hypercube.Utilities.Extensions;
using Hypercube.Utilities.Serialization.Hml.Core.Nodes.Value;
using JetBrains.Annotations;

namespace Hypercube.Utilities.Helpers;
Expand Down Expand Up @@ -262,7 +260,7 @@ public static IReadOnlyList<ValueInfo> GetValueInfos(Type type, BindingFlags? fl

foreach (var info in type.GetFields((BindingFlags) flags))
{
if (info.Name.Contains("k__BackingField"))
if (info.Name.Contains("k__BackingField") || info.Name.Contains("i__Field"))
continue;

if (Attribute.IsDefined(info, typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)))
Expand Down
4 changes: 4 additions & 0 deletions src/Hypercube.Utilities/Hypercube.Utilities.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,9 @@
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2025.2.2" />
</ItemGroup>

<ItemGroup>
<Folder Include="Serialization\Hml\Core\Formater\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Hypercube.Utilities.Serialization.Hml.Core.Nodes;

namespace Hypercube.Utilities.Serialization.Hml.Core.CompilerTypes;

public record BuildAstStackFrame()
{
public required Node Node;
public required Node Parent;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Hypercube.Utilities.Serialization.Hml.Core.Nodes;

namespace Hypercube.Utilities.Serialization.Hml.Core.CompilerTypes;

public record RenderAstStackFrame
{
public INode Node;
public int State;
public int Index;

public RenderAstStackFrame(INode node)
{
Node = node;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Hypercube.Utilities.Serialization.Hml.Core.CompilerTypes;

public class RenderAstState
{
public string Indent { get; private set; } = string.Empty;
public int IndentSize { get; init; }

public void PushIndent()
{
Indent += new string(' ', IndentSize);
}

public void PopIndent()
{
Indent = Indent.Remove(Indent.Length - IndentSize);
}
}
164 changes: 73 additions & 91 deletions src/Hypercube.Utilities/Serialization/Hml/Core/HmlCompiler.cs
Original file line number Diff line number Diff line change
@@ -1,123 +1,119 @@
using System.Collections;
using System.Text;
using System.Text.Json;
using Hypercube.Utilities.Helpers;
using Hypercube.Utilities.Serialization.Hml.Core.CompilerTypes;
using Hypercube.Utilities.Serialization.Hml.Core.Nodes;
using Hypercube.Utilities.Serialization.Hml.Core.Nodes.Value;
using Hypercube.Utilities.Serialization.Hml.Core.Nodes.Value.Primitives;

namespace Hypercube.Utilities.Serialization.Hml.Core;

public static class HmlCompiler
{
private record StackItem(object? Obj, int Indent, string? Name, bool IsClosing = false, bool Enumerated = false);

public static StringBuilder Serialize(object? obj, HmlSerializerOptions options)
{
var builder = new StringBuilder();
var stack = new Stack<StackItem>();

stack.Push(new StackItem(obj, 0, null));
var stack = new Stack<object?>();
var nodeQueue = new Queue<Node>();
stack.Push(obj);

while (stack.Count > 0)
{
var current = stack.Pop();
var indent = new string(' ', current.Indent * options.IndentSize);

if (current.IsClosing)
if (current is Node currentNode)
{
builder.Append(indent);

if (current.Obj is not null)
builder.Append(current.Obj);

if (current.Enumerated)
builder.Append(',');

builder.AppendLine();
nodeQueue.Enqueue(currentNode);
continue;
}

if (current.Obj is null)
if (current is null)
{
builder.Append(indent);

if (current.Name is not null)
{
builder.Append(current.Name);
builder.Append(": ");
}

builder.AppendLine(current.Enumerated ? "null," : "null");
nodeQueue.Enqueue(new NullValueNode());
continue;
}

var type = current.Obj.GetType();
if (IsSimpleType(current.Obj) || IsStringType(current.Obj))

if (IsSimpleType(current) || IsStringType(current))
{
builder.Append(indent);

if (current.Name is not null)
PrimitiveValueNode node = current switch
{
builder.Append(current.Name);
builder.Append(": ");
}

builder.Append(FormatValue(current.Obj, in options));

if (current.Enumerated)
builder.Append(',');
bool value => new BoolValue() { Value = value },
decimal value => new NumberValueNode() { Value = value},
float value => new NumberValueNode() { Value = (decimal)value},
double value => new NumberValueNode() { Value = (decimal)value},
string value => new StringValueNode() { Value = value},
char value => new StringValueNode() { Value = $"{value}"},
_ => new UnknownValueNode() { Value = current! }
};

builder.AppendLine();
nodeQueue.Enqueue(node);
continue;
}

if (current.Obj is IEnumerable enumerable)
{
builder.Append(indent);

if (current.Name is not null)
{
builder.Append(current.Name);
builder.Append(": ");
}

builder.Append('[');
builder.AppendLine();
if (current is IList list)
{
nodeQueue.Enqueue(new ListNode());

var items = new List<object>();
foreach (var e in enumerable)
items.Add(e!);
stack.Push(new EndNode());

stack.Push(new StackItem("]", current.Indent, null, true, Enumerated: current.Enumerated));
for (var i = items.Count - 1; i >= 0; i--)
stack.Push(new StackItem(items[i], current.Indent + 1, null, Enumerated: i != items.Count - 1 || options.TrailingComma));
for (var i = list.Count - 1; i >= 0; i--)
stack.Push(list[i]);

continue;
}

builder.Append(indent);

if (current.Name is not null)
{
builder.Append(current.Name);
builder.Append(": ");
}

builder.Append('{');
builder.AppendLine();

var type = current.GetType();
var values = ReflectionHelper.GetValueInfos(type);

stack.Push(new StackItem("}", current.Indent, null, true, Enumerated: current.Enumerated));
nodeQueue.Enqueue(new ObjectNode());
stack.Push(new EndNode());

for (var i = values.Count - 1; i >= 0; i--)
{
var valueInfo = values[i];
var value = valueInfo.GetValue(current.Obj);
stack.Push(new StackItem(value!, current.Indent + 1, valueInfo.Name));
var value = valueInfo.GetValue(current);

stack.Push(value);
stack.Push(new IdentifierNode { Name = valueInfo.Name });
stack.Push(new KeyValuePairNode());
}
}

return RenderAst(BuildAst(nodeQueue), options);
}

private static RootNode BuildAst(Queue<Node> nodes)
{
var stack = new Stack<BuildAstStackFrame>();
var ast = new RootNode();
stack.Push(new BuildAstStackFrame { Node = ast, Parent = null! });

while (stack.Count > 0)
{
var frame = stack.Pop();

frame.Node.Parent = frame.Parent;
frame.Node.OnBuild(stack, nodes, frame);
}

return builder;
return ast;
}

private static StringBuilder RenderAst(RootNode ast, HmlSerializerOptions options)
{
var state = new RenderAstState() { IndentSize = options.IndentSize};
var result = new StringBuilder();
var stack = new Stack<RenderAstStackFrame>();
stack.Push(new RenderAstStackFrame(ast));

while (stack.Count > 0)
{
var frame = stack.Pop();
result.Append(frame.Node.Render(stack, result, frame, state, options));
}

return result;
}

private static bool IsSimpleType(object obj)
{
var type = obj.GetType();
Expand All @@ -129,18 +125,4 @@ private static bool IsStringType(object obj)
var type = obj.GetType();
return type == typeof(string) || type == typeof(char);
}

private static string FormatValue(object obj, in HmlSerializerOptions options)
{
return obj switch
{
bool value => value ? "true" : "false",
decimal value => value.ToString(options.CultureInfo),
float value => value.ToString(options.CultureInfo),
double value => value.ToString(options.CultureInfo),
string value => $"'{value}'",
char value => $"'{value}'",
_ => obj.ToString()!
};
}
}
Loading