Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ast api #47

Merged
merged 19 commits into from
Jan 22, 2024
Merged
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
1 change: 1 addition & 0 deletions Linguini.Bench/Linguini.Bench.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<PackageVersion>0.8.0</PackageVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion Linguini.Bundle.Test/Linguini.Bundle.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<OutputType>Library</OutputType>
<PackageVersion>0.7.0</PackageVersion>
<PackageVersion>0.8.0</PackageVersion>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
</PropertyGroup>

Expand Down
13 changes: 6 additions & 7 deletions Linguini.Bundle/Errors/FluentError.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using Linguini.Shared.Util;
using Linguini.Syntax.Ast;
using Linguini.Syntax.Parser.Error;

Expand Down Expand Up @@ -51,23 +50,23 @@ public override string ToString()

public record ResolverFluentError : FluentError
{
private string Description;
private ErrorType Kind;
private readonly string _description;
private readonly ErrorType _kind;

private ResolverFluentError(string desc, ErrorType kind)
{
Description = desc;
Kind = kind;
_description = desc;
_kind = kind;
}

public override ErrorType ErrorKind()
{
return Kind;
return _kind;
}

public override string ToString()
{
return Description;
return _description;
}

public static ResolverFluentError NoValue(ReadOnlyMemory<char> idName)
Expand Down
2 changes: 1 addition & 1 deletion Linguini.Bundle/Linguini.Bundle.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ It provides easy to use and extend system for describing translations.</Descript
<Win32Resource />
<PackageProjectUrl>https://github.com/Ygg01/Linguini</PackageProjectUrl>
<RepositoryType>git</RepositoryType>
<PackageVersion>0.7.0</PackageVersion>
<PackageVersion>0.8.0</PackageVersion>
<TargetFrameworks>net8.0;netstandard2.1;net6.0</TargetFrameworks>
<PackageIcon>linguini.jpg</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down
63 changes: 20 additions & 43 deletions Linguini.Bundle/Resolver/WriterHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#nullable enable
using System;
using System;
using System.Collections.Generic;
using System.IO;
using Linguini.Bundle.Errors;
Expand Down Expand Up @@ -100,11 +99,9 @@ public static bool TryWrite(this IExpression expression, TextWriter writer, Scop
for (var i = 0; i < selectExpression.Variants.Count; i++)
{
var variant = selectExpression.Variants[i];
if (variant.IsDefault)
{
variant.Value.Write(writer, scope);
return errors.Count == 0;
}
if (!variant.IsDefault) continue;
variant.Value.Write(writer, scope);
return errors.Count == 0;
}

errors.Add(ResolverFluentError.MissingDefault());
Expand Down Expand Up @@ -312,46 +309,26 @@ public static void WriteError(this IExpression self, TextWriter writer)

public static void WriteError(this IInlineExpression self, TextWriter writer)
{
if (self is MessageReference msgRef)
switch (self)
{
if (msgRef.Attribute == null)
{
writer.Write($"{msgRef.Id}");
case MessageReference msgRef:
writer.Write(msgRef.Attribute == null ? $"{msgRef.Id}" : $"{msgRef.Id}.{msgRef.Attribute}");
return;
}

writer.Write($"{msgRef.Id}.{msgRef.Attribute}");
return;
}

if (self is TermReference termRef)
{
if (termRef.Attribute == null)
{
writer.Write($"-{termRef.Id}");
case TermReference termReference:
writer.Write(termReference.Attribute == null ? $"-{termReference.Id}" : $"-{termReference.Id}.{termReference.Attribute}");
return;
}

writer.Write($"-{termRef.Id}.{termRef.Attribute}");
}
else if (self is FunctionReference funcRef)
{
writer.Write($"{funcRef.Id}()");
return;
}
else if (self is VariableReference varRef)
{
writer.Write($"${varRef.Id}");
return;
}
else if (self is DynamicReference dynamicReference)
{
writer.Write($"$${dynamicReference.Id}");
return;
case FunctionReference funcRef:
writer.Write($"{funcRef.Id}()");
return;
case VariableReference varRef:
writer.Write($"${varRef.Id}");
return;
case DynamicReference dynamicReference:
writer.Write($"$${dynamicReference.Id}");
return;
default:
throw new ArgumentException($"Unexpected inline expression `{self.GetType()}`!");
}


throw new ArgumentException($"Unexpected inline expression `{self.GetType()}`!");
}
}
}
20 changes: 20 additions & 0 deletions Linguini.Serialization.Test/Linguini.Serialization.Test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>10</LangVersion>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Linguini.Serialization\Linguini.Serialization.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
</ItemGroup>

</Project>
105 changes: 105 additions & 0 deletions Linguini.Serialization.Test/SerializeAndDeserializeTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System.Diagnostics;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using Linguini.Serialization.Converters;
using Linguini.Syntax.Ast;
using NUnit.Framework;
using Attribute = Linguini.Syntax.Ast.Attribute;


namespace Linguini.Serialization.Test;

[TestFixture]
public class SerializeAndDeserializeTest
{
[Test]
[TestCaseSource(nameof(AstExamples))]
[Parallelizable]
public void RoundTripTest(object x)
{
// Serialize the object to JSON string.
var jsonString = JsonSerializer.Serialize(x, Options);

// Deserialize the JSON string back into an object.
Debug.Assert(x != null, nameof(x) + " != null");
var deserializedObject = JsonSerializer.Deserialize(jsonString, x.GetType(), Options);

// Now you have a 'deserializedObject' which should be equivalent to the original 'expected' object.
Assert.That(deserializedObject, Is.Not.Null);
Assert.That(deserializedObject, Is.EqualTo(x));
}

public static IEnumerable<object> AstExamples()
{
yield return new Attribute("desc", new PatternBuilder("description"));
yield return new CallArgumentsBuilder()
.AddPositionalArg(InlineExpressionBuilder.CreateMessageReference("x"))
.AddNamedArg("y", 3)
.Build();
yield return new AstComment(CommentLevel.Comment, new() { "test".AsMemory() });
yield return new DynamicReference("dyn", "attr", new CallArgumentsBuilder()
.AddPositionalArg(InlineExpressionBuilder.CreateMessageReference("x"))
.AddNamedArg("y", 3));
yield return new FunctionReference("foo", new CallArgumentsBuilder()
.AddPositionalArg(3)
.AddNamedArg("test", InlineExpressionBuilder.CreateTermReference("x", "y"))
.Build()
);
yield return new Identifier("test");
yield return new Junk("Test".AsMemory());
yield return new MessageReference("message", "attribute");
yield return new AstMessage(
new Identifier("x"),
new PatternBuilder(3).Build(),
new List<Attribute>()
{
new("attr1", new PatternBuilder("value1")),
new("attr2", new PatternBuilder("value2"))
},
new(CommentLevel.ResourceComment, new()
{
"test".AsMemory()
}));
yield return new PatternBuilder("text ").AddMessage("x").AddText(" more text").Build();
yield return new SelectExpressionBuilder(new VariableReference("x"))
.AddVariant("one", new PatternBuilder("select 1"))
.AddVariant("other", new PatternBuilder("select other"))
.SetDefault(1)
.Build();
yield return new TermReference("x", "y");
yield return new VariableReference("x");
yield return new Variant(2.0f, new PatternBuilder(3));
}

private static readonly JsonSerializerOptions Options = new()
{
IgnoreReadOnlyFields = false,
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters =
{
new AttributeSerializer(),
new CallArgumentsSerializer(),
new CommentSerializer(),
new FunctionReferenceSerializer(),
new IdentifierSerializer(),
new JunkSerializer(),
new MessageReferenceSerializer(),
new MessageSerializer(),
new DynamicReferenceSerializer(),
new NamedArgumentSerializer(),
new ParseErrorSerializer(),
new PatternSerializer(),
new PlaceableSerializer(),
new ResourceSerializer(),
new PlaceableSerializer(),
new SelectExpressionSerializer(),
new TermReferenceSerializer(),
new TermSerializer(),
new VariantSerializer(),
new VariableReferenceSerializer(),
}
};
}
16 changes: 16 additions & 0 deletions Linguini.Serialization.Test/TestUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using Linguini.Serialization.Converters;
using NUnit.Framework;

namespace Linguini.Serialization.Test
{
public static class TestUtil
{




}
}
48 changes: 47 additions & 1 deletion Linguini.Serialization/Converters/AttributeSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using Linguini.Syntax.Ast;
using Attribute = Linguini.Syntax.Ast.Attribute;

namespace Linguini.Serialization.Converters
Expand All @@ -9,7 +10,52 @@ public class AttributeSerializer : JsonConverter<Attribute>
{
public override Attribute Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}

var id = new Identifier("");
var value = new Pattern();

while (reader.Read())
{

if (reader.TokenType == JsonTokenType.EndObject)
{
break;
}

if (reader.TokenType == JsonTokenType.PropertyName)
{
string? propertyName = reader.GetString();

reader.Read();

switch (propertyName)
{
case "id":
id = JsonSerializer.Deserialize<Identifier>(ref reader, options);
break;

case "value":
value = JsonSerializer.Deserialize<Pattern>(ref reader, options);
break;
case "type":
var typeField = reader.GetString();
if (typeField != "Attribute")
{
throw new JsonException(
$"Invalid type: Expected 'Attribute' found {typeField} instead");
}
break;
default:
throw new JsonException($"Unexpected property: {propertyName}");
}
}
}

return new Attribute(id!, value!);
}

public override void Write(Utf8JsonWriter writer, Attribute attribute, JsonSerializerOptions options)
Expand Down
Loading
Loading