Optimised structs

This commit is contained in:
mdnapo 2024-09-16 20:12:48 +02:00
parent 23324a2b53
commit 74a141277e
47 changed files with 665 additions and 631 deletions

View File

@ -86,8 +86,8 @@ public class JsonParserTests
[ [
JsonNumber { Value: 1 }, JsonNumber { Value: 1 },
JsonBool { Value: true }, JsonBool { Value: true },
JsonObject { Properties: null}, JsonObject { Properties.Length: 0 },
JsonArray { Elements: null }, JsonArray { Elements.Length: 0 },
JsonNull JsonNull
] ]
}); });
@ -98,19 +98,19 @@ public class JsonParserTests
{ {
const string source = "{}"; const string source = "{}";
var tokens = JsonParser.Parse(nameof(Can_parse_an_empty_object), source); var tokens = JsonParser.Parse(nameof(Can_parse_an_empty_object), source);
Assert.That(tokens is JsonObject { Properties: null }); Assert.That(tokens is JsonObject { Properties.Length: 0 });
} }
[Test] [Test]
public void Can_parse_an_object_with_one_entry() public void Can_parse_an_object_with_one_entry()
{ {
const string source = "{\"first_name\":\"John\nDoe\"}"; const string source = "{\"first_name\":\"John\"}";
var node = JsonParser.Parse(nameof(Can_parse_an_object_with_one_entry), source); var node = JsonParser.Parse(nameof(Can_parse_an_object_with_one_entry), source);
Assert.That(node is JsonObject { Properties.Count: 1 }); Assert.That(node is JsonObject { Properties.Length: 1 });
var @object = (JsonObject)node; var @object = (JsonObject)node;
Assert.That(@object.Properties.ContainsKey("first_name")); Assert.That(@object.Properties.Any(property => property.Key == "first_name"));
Assert.That(@object.Properties["first_name"] is JsonString { Value: "John" }); Assert.That(@object.Properties.First(property => property.Key == "first_name").Value is JsonString { Value: "John" });
} }
[Test] [Test]
@ -121,12 +121,12 @@ public class JsonParserTests
Assert.Multiple(() => Assert.Multiple(() =>
{ {
Assert.That(node is JsonObject { Properties.Count: 2 }); Assert.That(node is JsonObject { Properties.Length: 2 });
var @object = (JsonObject)node; var @object = (JsonObject)node;
Assert.That(@object.Properties.ContainsKey("first_name")); Assert.That(@object.Properties.Any(property => property.Key == "first_name"));
Assert.That(@object.Properties["first_name"] is JsonString { Value: "John" }); Assert.That(@object.Properties.First(property => property.Key == "first_name").Value is JsonString { Value: "John" });
Assert.That(@object.Properties.ContainsKey("last_name")); Assert.That(@object.Properties.Any(property => property.Key == "last_name"));
Assert.That(@object.Properties["last_name"] is JsonString { Value: "Doe" }); Assert.That(@object.Properties.First(property => property.Key == "last_name").Value is JsonString { Value: "Doe" });
}); });
} }
} }

View File

@ -2,14 +2,14 @@ using DevDisciples.Parsing;
namespace DevDisciples.Json.Parser; namespace DevDisciples.Json.Parser;
public struct JsonArray : ISyntaxNode public readonly struct JsonArray : ISyntaxNode
{ {
public Lexer<JsonToken>.Token Token { get; } public Lexer<JsonToken>.Token Token { get; }
public List<ISyntaxNode> Elements { get; } public ISyntaxNode[] Elements { get; }
public JsonArray(Lexer<JsonToken>.Token token, List<ISyntaxNode>? elements) public JsonArray(Lexer<JsonToken>.Token token, ISyntaxNode[] elements)
{ {
Token = token; Token = token;
Elements = elements ?? new(); Elements = elements;
} }
} }

View File

@ -2,7 +2,7 @@ using DevDisciples.Parsing;
namespace DevDisciples.Json.Parser; namespace DevDisciples.Json.Parser;
public struct JsonBool : ISyntaxNode public readonly struct JsonBool : ISyntaxNode
{ {
public Lexer<JsonToken>.Token Token { get; } public Lexer<JsonToken>.Token Token { get; }
public bool Value => bool.TryParse(Token.Lexeme, out var val) && val; public bool Value => bool.TryParse(Token.Lexeme, out var val) && val;

View File

@ -2,7 +2,7 @@ using DevDisciples.Parsing;
namespace DevDisciples.Json.Parser; namespace DevDisciples.Json.Parser;
public struct JsonNull : ISyntaxNode public readonly struct JsonNull : ISyntaxNode
{ {
public Lexer<JsonToken>.Token Token { get; } public Lexer<JsonToken>.Token Token { get; }

View File

@ -2,7 +2,7 @@ using DevDisciples.Parsing;
namespace DevDisciples.Json.Parser; namespace DevDisciples.Json.Parser;
public struct JsonNumber : ISyntaxNode public readonly struct JsonNumber : ISyntaxNode
{ {
public Lexer<JsonToken>.Token Token { get; } public Lexer<JsonToken>.Token Token { get; }
public double Value => double.TryParse(Token.Lexeme.Replace('.', ','), out var val) ? val : default; public double Value => double.TryParse(Token.Lexeme.Replace('.', ','), out var val) ? val : default;

View File

@ -0,0 +1,18 @@
using DevDisciples.Parsing;
namespace DevDisciples.Json.Parser;
public readonly partial struct JsonObject
{
public readonly struct Property : ISyntaxNode
{
public string Key { get; }
public ISyntaxNode Value { get; }
public Property(string key, ISyntaxNode value)
{
Key = key;
Value = value;
}
}
}

View File

@ -2,14 +2,14 @@ using DevDisciples.Parsing;
namespace DevDisciples.Json.Parser; namespace DevDisciples.Json.Parser;
public struct JsonObject : ISyntaxNode public readonly partial struct JsonObject : ISyntaxNode
{ {
public Lexer<JsonToken>.Token Token { get; } public Lexer<JsonToken>.Token Token { get; }
public Dictionary<string, ISyntaxNode> Properties { get; set; } public Property[] Properties { get; }
public JsonObject(Lexer<JsonToken>.Token token, Dictionary<string, ISyntaxNode>? properties) public JsonObject(Lexer<JsonToken>.Token token, Property[] properties)
{ {
Token = token; Token = token;
Properties = properties ?? new(); Properties = properties;
} }
} }

View File

@ -51,7 +51,7 @@ public static partial class JsonParser
ctx.Consume(JsonToken.RightBracket, "Expected ']'"); ctx.Consume(JsonToken.RightBracket, "Expected ']'");
return new JsonArray(previous, elements); return new JsonArray(previous, elements?.ToArray() ?? System.Array.Empty<ISyntaxNode>());
} }
private static ISyntaxNode Object(ParserContext<JsonToken> ctx) private static ISyntaxNode Object(ParserContext<JsonToken> ctx)
@ -72,7 +72,9 @@ public static partial class JsonParser
ctx.Consume(JsonToken.RightBrace, "Expected '}'"); ctx.Consume(JsonToken.RightBrace, "Expected '}'");
return new JsonObject(previous, properties); var propertiesArray = properties?.Select(kv => new JsonObject.Property(kv.Key, kv.Value)).ToArray();
return new JsonObject(previous, propertiesArray ?? System.Array.Empty<JsonObject.Property>());
} }
private static ISyntaxNode Number(ParserContext<JsonToken> ctx) private static ISyntaxNode Number(ParserContext<JsonToken> ctx)

View File

@ -2,7 +2,7 @@ using DevDisciples.Parsing;
namespace DevDisciples.Json.Parser; namespace DevDisciples.Json.Parser;
public struct JsonString : ISyntaxNode public readonly struct JsonString : ISyntaxNode
{ {
public Lexer<JsonToken>.Token Token { get; } public Lexer<JsonToken>.Token Token { get; }
public string Value => Token.Lexeme; public string Value => Token.Lexeme;

View File

@ -2,6 +2,6 @@
public class Json2CsharpRequest : TransformRequest public class Json2CsharpRequest : TransformRequest
{ {
public string RootClassName { get; set; } = Json2CSharpTranslator.Context.DefaultRootClassName; public string RootClassName { get; } = Json2CSharpTranslator.Context.DefaultRootClassName;
public string Namespace { get; set; } = Json2CSharpTranslator.Context.DefaultNamespace; public string Namespace { get; } = Json2CSharpTranslator.Context.DefaultNamespace;
} }

View File

@ -2,5 +2,5 @@
public class PrettifyRequest : TransformRequest public class PrettifyRequest : TransformRequest
{ {
public int IndentSize { get; set; } = JsonFormatter.Context.DefaultIndentSize; public int IndentSize { get; } = JsonFormatter.Context.DefaultIndentSize;
} }

View File

@ -2,5 +2,5 @@
public abstract class TransformRequest public abstract class TransformRequest
{ {
public string Source { get; set; } = string.Empty; public string Source { get; init; } = string.Empty;
} }

View File

@ -12,14 +12,14 @@ export class JsonTransformService {
} }
public prettify(source: string): Observable<HttpResponse<any>> { public prettify(source: string): Observable<HttpResponse<any>> {
return this.http.post(`${this.url}/api/transform/prettify`, {source: source}, {observe: "response"}); return this.http.post(`${this.url}/api/transform/prettify`, {Source: source}, {observe: "response"});
} }
public uglify(source: string): Observable<HttpResponse<any>> { public uglify(source: string): Observable<HttpResponse<any>> {
return this.http.post(`${this.url}/api/transform/uglify`, {source: source}, {observe: "response"}); return this.http.post(`${this.url}/api/transform/uglify`, {Source: source}, {observe: "response"});
} }
public json2csharp(source: string): Observable<HttpResponse<any>> { public json2csharp(source: string): Observable<HttpResponse<any>> {
return this.http.post(`${this.url}/api/transform/json2csharp`, {source: source}, {observe: "response"}); return this.http.post(`${this.url}/api/transform/json2csharp`, {Source: source}, {observe: "response"});
} }
} }

View File

@ -1,4 +1,4 @@
import {Component, OnInit} from '@angular/core'; import {AfterViewInit, Component, OnInit} from '@angular/core';
import {InputOutputComponent} from "../input-output/input-output.component"; import {InputOutputComponent} from "../input-output/input-output.component";
import {JsonTransformService} from "../json-transform.service"; import {JsonTransformService} from "../json-transform.service";
@ -11,7 +11,7 @@ import {JsonTransformService} from "../json-transform.service";
templateUrl: './json2-csharp.component.html', templateUrl: './json2-csharp.component.html',
styleUrl: './json2-csharp.component.scss' styleUrl: './json2-csharp.component.scss'
}) })
export class Json2CsharpComponent implements OnInit { export class Json2CsharpComponent implements AfterViewInit {
input: string = JSON.stringify({first_name: "John", last_name: "Doe"}, null, 2); input: string = JSON.stringify({first_name: "John", last_name: "Doe"}, null, 2);
inputOptions = {theme: 'vs-dark', language: 'json', readOnly: false}; inputOptions = {theme: 'vs-dark', language: 'json', readOnly: false};
output: string = JSON.stringify({first_name: "John", last_name: "Doe"}); output: string = JSON.stringify({first_name: "John", last_name: "Doe"});
@ -20,7 +20,7 @@ export class Json2CsharpComponent implements OnInit {
constructor(private service: JsonTransformService) { constructor(private service: JsonTransformService) {
} }
ngOnInit(): void { ngAfterViewInit(): void {
this.service this.service
.json2csharp(this.input) .json2csharp(this.input)
.subscribe(response => { .subscribe(response => {
@ -34,6 +34,20 @@ export class Json2CsharpComponent implements OnInit {
}); });
} }
ngOnInit(): void {
// this.service
// .json2csharp(this.input)
// .subscribe(response => {
// console.log(response);
//
// if (response.status === 200) {
// this.output = response.body.result;
// } else if (response.status === 499) {
// this.output = response.body.detail;
// }
// });
}
handleInputChange($event: any) { handleInputChange($event: any) {
console.log($event); console.log($event);
this.service this.service

View File

@ -4,7 +4,7 @@ public partial class Json2CSharpCommand
{ {
public class CommandOptions : CLI.CommandOptions public class CommandOptions : CLI.CommandOptions
{ {
public string? RootClassName { get; set; } public string? RootClassName { get; init; }
public string? Namespace { get; set; } public string? Namespace { get; init; }
} }
} }

View File

@ -4,6 +4,6 @@ public partial class JsonPrettifyCommand
{ {
public class CommandOptions : CLI.CommandOptions public class CommandOptions : CLI.CommandOptions
{ {
public int IndentSize { get; set; } public int IndentSize { get; init; }
} }
} }

View File

@ -4,10 +4,10 @@ namespace DevDisciples.Json.Tools;
public static partial class Json2CSharpTranslator public static partial class Json2CSharpTranslator
{ {
public struct ClassTranslation : ITranslation public readonly struct ClassTranslation : ITranslation
{ {
public string Name { get; set; } public string Name { get; init; }
public List<PropertyTranslation> Properties { get; set; } public List<PropertyTranslation> Properties { get; init; }
public void Translate(Context context) public void Translate(Context context)
{ {

View File

@ -9,9 +9,9 @@ public static partial class Json2CSharpTranslator
public const string DefaultRootClassName = "Root"; public const string DefaultRootClassName = "Root";
public const string DefaultNamespace = "My.Namespace"; public const string DefaultNamespace = "My.Namespace";
public string RootClassName { get; set; } = DefaultRootClassName; public string RootClassName { get; init; } = DefaultRootClassName;
public string Namespace { get; set; } = DefaultNamespace; public string Namespace { get; init; } = DefaultNamespace;
public List<ClassTranslation> Classes { get; set; } = new(); public List<ClassTranslation> Classes { get; } = new();
public readonly StringBuilder Builder = new(); public readonly StringBuilder Builder = new();
} }
} }

View File

@ -40,7 +40,7 @@ public static partial class Json2CSharpTranslator
}; };
} }
private static ClassTranslation SquashObjects(string className, List<ISyntaxNode> objects, object[] args) private static ClassTranslation SquashObjects(string className, IEnumerable<ISyntaxNode> objects, object[] args)
{ {
var classes = objects var classes = objects
.Select(@object => JsonObjectTranslator.Translate(@object, args)) .Select(@object => JsonObjectTranslator.Translate(@object, args))

View File

@ -4,10 +4,10 @@ namespace DevDisciples.Json.Tools;
public static partial class Json2CSharpTranslator public static partial class Json2CSharpTranslator
{ {
public struct PropertyTranslation : ITranslation public readonly struct PropertyTranslation : ITranslation
{ {
public string Name { get; set; } public string Name { get; init; }
public string Type { get; set; } public string Type { get; init; }
public void Translate(Context context) public void Translate(Context context)
{ {

View File

@ -9,10 +9,10 @@ public static partial class JsonFormatter
public const int DefaultIndentSize = 2; public const int DefaultIndentSize = 2;
protected int Depth { get; set; } = 0; protected int Depth { get; set; } = 0;
public StringBuilder Builder { get; set; } = new(); public StringBuilder Builder { get; } = new();
public bool Beautify { get; set; } = false; public bool Beautify { get; init; } = false;
public string Indent => new(' ', Depth); public string Indent => new(' ', Depth);
public int IndentSize { get; set; } = DefaultIndentSize; public int IndentSize { get; init; } = DefaultIndentSize;
public string NewLine => Beautify ? "\n" : ""; public string NewLine => Beautify ? "\n" : "";
public string Space => Beautify ? " " : ""; public string Space => Beautify ? " " : "";

View File

@ -44,12 +44,12 @@ public static partial class JsonFormatter
context.Builder.Append($"[{context.NewLine}"); context.Builder.Append($"[{context.NewLine}");
context.IncrementDepth(); context.IncrementDepth();
for (var i = 0; i < array.Elements.Count; i++) for (var i = 0; i < array.Elements.Length; i++)
{ {
var node = array.Elements[i]; var node = array.Elements[i];
context.Builder.Append(context.Indent); context.Builder.Append(context.Indent);
Visitors[node.GetType()](node, args); Visitors[node.GetType()](node, args);
if (i < array.Elements.Count - 1) context.Builder.Append($",{context.NewLine}"); if (i < array.Elements.Length - 1) context.Builder.Append($",{context.NewLine}");
} }
context.DecrementDepth(); context.DecrementDepth();
@ -64,12 +64,12 @@ public static partial class JsonFormatter
context.Builder.Append($"{{{context.NewLine}"); context.Builder.Append($"{{{context.NewLine}");
context.IncrementDepth(); context.IncrementDepth();
var count = @object.Properties.Count; var count = @object.Properties.Length;
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var (key, node) = @object.Properties.ElementAt(i); var property = @object.Properties.ElementAt(i);
context.Builder.Append($"{context.Indent}\"{key}\":{context.Space}"); context.Builder.Append($"{context.Indent}\"{property.Key}\":{context.Space}");
Visitors[node.GetType()](node, args); Visitors[property.Value.GetType()](property.Value, args);
if (i < count - 1) context.Builder.Append($",{context.NewLine}"); if (i < count - 1) context.Builder.Append($",{context.NewLine}");
} }

View File

@ -2,7 +2,7 @@
public abstract partial class Lexer<TToken> where TToken : Enum public abstract partial class Lexer<TToken> where TToken : Enum
{ {
public struct Token : ISourceLocation public readonly struct Token : ISourceLocation
{ {
public string File { get; } public string File { get; }
public TToken Type { get; } public TToken Type { get; }

View File

@ -16,7 +16,7 @@ public class VisitorContainer
public class VisitorContainer<T> public class VisitorContainer<T>
{ {
protected Dictionary<Type, Visitor.Visit<T>> Visitors { get; } = new(); protected Dictionary<Type, Visitor.Visit<T>> Visitors { get; } = new();
public Visitor.Visit<T> Default { get; set; } = default!; public Visitor.Visit<T> Default { get; } = default!;
public VisitorContainer<T> Register<TVisitee>(Visitor.Visit<T> visitor) public VisitorContainer<T> Register<TVisitee>(Visitor.Visit<T> visitor)
@ -31,7 +31,7 @@ public class VisitorContainer<T>
public class VisitorContainer<TIn, TOut> public class VisitorContainer<TIn, TOut>
{ {
protected Dictionary<Type, Visitor.Visit<TIn, TOut>> Visitors { get; } = new(); protected Dictionary<Type, Visitor.Visit<TIn, TOut>> Visitors { get; } = new();
public Visitor.Visit<TIn, TOut> Default { get; set; } = default!; public Visitor.Visit<TIn, TOut> Default { get; } = default!;
public void Register<TVisitee>(Visitor.Visit<TIn, TOut> visitor) public void Register<TVisitee>(Visitor.Visit<TIn, TOut> visitor)
{ {