diff --git a/Linguini.Bench/Linguini.Bench.csproj b/Linguini.Bench/Linguini.Bench.csproj
index bfe1545..8d1a815 100644
--- a/Linguini.Bench/Linguini.Bench.csproj
+++ b/Linguini.Bench/Linguini.Bench.csproj
@@ -4,6 +4,7 @@
Exe
false
net6.0;net8.0
+ 0.8.0
diff --git a/Linguini.Bundle.Test/Linguini.Bundle.Test.csproj b/Linguini.Bundle.Test/Linguini.Bundle.Test.csproj
index 8ad1b66..2311158 100644
--- a/Linguini.Bundle.Test/Linguini.Bundle.Test.csproj
+++ b/Linguini.Bundle.Test/Linguini.Bundle.Test.csproj
@@ -4,7 +4,7 @@
false
enable
Library
- 0.7.0
+ 0.8.0
net6.0;net8.0
diff --git a/Linguini.Bundle/Errors/FluentError.cs b/Linguini.Bundle/Errors/FluentError.cs
index fc2a097..86c3df7 100644
--- a/Linguini.Bundle/Errors/FluentError.cs
+++ b/Linguini.Bundle/Errors/FluentError.cs
@@ -1,5 +1,4 @@
using System;
-using Linguini.Shared.Util;
using Linguini.Syntax.Ast;
using Linguini.Syntax.Parser.Error;
@@ -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 idName)
diff --git a/Linguini.Bundle/Linguini.Bundle.csproj b/Linguini.Bundle/Linguini.Bundle.csproj
index 9915581..69b93d4 100644
--- a/Linguini.Bundle/Linguini.Bundle.csproj
+++ b/Linguini.Bundle/Linguini.Bundle.csproj
@@ -18,7 +18,7 @@ It provides easy to use and extend system for describing translations.
https://github.com/Ygg01/Linguini
git
- 0.7.0
+ 0.8.0
net8.0;netstandard2.1;net6.0
linguini.jpg
README.md
diff --git a/Linguini.Bundle/Resolver/WriterHelpers.cs b/Linguini.Bundle/Resolver/WriterHelpers.cs
index 7f7f18c..ddaeed1 100644
--- a/Linguini.Bundle/Resolver/WriterHelpers.cs
+++ b/Linguini.Bundle/Resolver/WriterHelpers.cs
@@ -1,5 +1,4 @@
-#nullable enable
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using Linguini.Bundle.Errors;
@@ -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());
@@ -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()}`!");
}
}
}
\ No newline at end of file
diff --git a/Linguini.Serialization.Test/Linguini.Serialization.Test.csproj b/Linguini.Serialization.Test/Linguini.Serialization.Test.csproj
new file mode 100644
index 0000000..f527355
--- /dev/null
+++ b/Linguini.Serialization.Test/Linguini.Serialization.Test.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net8.0
+ enable
+ enable
+ 10
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Linguini.Serialization.Test/SerializeAndDeserializeTest.cs b/Linguini.Serialization.Test/SerializeAndDeserializeTest.cs
new file mode 100644
index 0000000..ac91a89
--- /dev/null
+++ b/Linguini.Serialization.Test/SerializeAndDeserializeTest.cs
@@ -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
-
-
-
-
diff --git a/Linguini.Shared/Linguini.Shared.csproj b/Linguini.Shared/Linguini.Shared.csproj
index 6d525a3..597cc20 100644
--- a/Linguini.Shared/Linguini.Shared.csproj
+++ b/Linguini.Shared/Linguini.Shared.csproj
@@ -9,7 +9,7 @@
MIT OR Apache-2.0
fluent, i18n, internationalization, l10n, l20n, globalization, translation
false
- 0.7.0
+ 0.8.0
net6.0;netstandard2.1;net8.0
linguini.jpg
README.md
diff --git a/Linguini.Syntax.Tests/Linguini.Syntax.Tests.csproj b/Linguini.Syntax.Tests/Linguini.Syntax.Tests.csproj
index 3599ec3..ae7fb81 100644
--- a/Linguini.Syntax.Tests/Linguini.Syntax.Tests.csproj
+++ b/Linguini.Syntax.Tests/Linguini.Syntax.Tests.csproj
@@ -6,6 +6,7 @@
Library
linguini.jpg
net6.0;net8.0
+ 0.8.0
diff --git a/Linguini.Syntax.Tests/Parser/LinguiniFtlParserTest.cs b/Linguini.Syntax.Tests/Parser/LinguiniFtlParserTest.cs
index b4c3dc5..485bfb8 100644
--- a/Linguini.Syntax.Tests/Parser/LinguiniFtlParserTest.cs
+++ b/Linguini.Syntax.Tests/Parser/LinguiniFtlParserTest.cs
@@ -1,10 +1,8 @@
-#nullable enable
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.IO;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
-using FluentAssertions.Execution;
using FluentAssertions.Json;
using Linguini.Serialization.Converters;
using Linguini.Syntax.Ast;
@@ -37,9 +35,8 @@ private static string BaseTestDir
}
}
- private static JsonSerializerOptions TestJsonOptions()
- {
- return new JsonSerializerOptions
+ private static JsonSerializerOptions TestJsonOptions =
+ new()
{
IgnoreReadOnlyFields = false,
WriteIndented = true,
@@ -69,7 +66,6 @@ private static JsonSerializerOptions TestJsonOptions()
new VariableReferenceSerializer(),
},
};
- }
private static string GetFullPathFor(string file)
{
@@ -117,7 +113,7 @@ public void TestLinguiniErrors(string file, bool ignoreComments = false)
? ParseFtlFileFast(@$"{path}.ftl")
: ParseFtlFile(@$"{path}.ftl");
- var actual = WrapArray(JArray.Parse(JsonSerializer.Serialize(resource.Errors, TestJsonOptions())));
+ var actual = WrapArray(JArray.Parse(JsonSerializer.Serialize(resource.Errors, TestJsonOptions)));
actual.Should().BeEquivalentTo(expected);
}
@@ -171,7 +167,7 @@ public void TestReadFile(string file)
{
var path = GetFullPathFor(file);
var res = ParseFtlFile(@$"{path}.ftl");
- var ftlAstJson = JsonSerializer.Serialize(res, TestJsonOptions());
+ var ftlAstJson = JsonSerializer.Serialize(res, TestJsonOptions);
var expected = JToken.Parse(File.ReadAllText($@"{path}.json"));
var actual = JToken.Parse(ftlAstJson);
@@ -223,7 +219,7 @@ public void TestLinguiniExt(string file)
{
var path = GetFullPathFor(file);
var res = ParseFtlFile(@$"{path}.ftl", true);
- var ftlAstJson = JsonSerializer.Serialize(res, TestJsonOptions());
+ var ftlAstJson = JsonSerializer.Serialize(res, TestJsonOptions);
var expected = JToken.Parse(File.ReadAllText($@"{path}.json"));
var actual = JToken.Parse(ftlAstJson);
diff --git a/Linguini.Syntax.Tests/Parser/LinguiniTestDetailedErrors.cs b/Linguini.Syntax.Tests/Parser/LinguiniTestDetailedErrors.cs
index d437bb7..d7581fd 100644
--- a/Linguini.Syntax.Tests/Parser/LinguiniTestDetailedErrors.cs
+++ b/Linguini.Syntax.Tests/Parser/LinguiniTestDetailedErrors.cs
@@ -1,8 +1,6 @@
using System;
-using Linguini.Syntax.Ast;
using Linguini.Syntax.Parser;
using NUnit.Framework;
-using NUnit.Framework.Legacy;
namespace Linguini.Syntax.Tests.Parser
{
diff --git a/Linguini.Syntax/Ast/Base.cs b/Linguini.Syntax/Ast/Base.cs
index 8d2a231..644de8b 100644
--- a/Linguini.Syntax/Ast/Base.cs
+++ b/Linguini.Syntax/Ast/Base.cs
@@ -2,14 +2,36 @@
using System.Collections.Generic;
using System.Text;
+// ReSharper disable ClassNeverInstantiated.Global
+// ReSharper disable UnusedMember.Global
+// ReSharper disable ForCanBeConvertedToForeach
namespace Linguini.Syntax.Ast
{
-
- public class Attribute
+ public class Attribute : IEquatable
{
- public Identifier Id;
- public Pattern Value;
+ public readonly Identifier Id;
+ public readonly Pattern Value;
+
+ public static AttributeComparer Comparer = new();
+
+ public class AttributeComparer : IEqualityComparer
+ {
+ public bool Equals(Attribute? x, Attribute? y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (ReferenceEquals(x, null)) return false;
+ if (ReferenceEquals(y, null)) return false;
+ if (x.GetType() != y.GetType()) return false;
+ return Identifier.Comparator.Equals(x.Id, y.Id) &&
+ x.Value.Equals(y.Value);
+ }
+
+ public int GetHashCode(Attribute obj)
+ {
+ return HashCode.Combine(obj.Id, obj.Value);
+ }
+ }
public Attribute(Identifier id, Pattern value)
{
@@ -17,16 +39,48 @@ public Attribute(Identifier id, Pattern value)
Value = value;
}
+ public Attribute(string id, PatternBuilder builder)
+ {
+ Id = new Identifier(id);
+ Value = builder.Build();
+ }
+
public void Deconstruct(out Identifier id, out Pattern value)
{
id = Id;
value = Value;
}
+
+ public static Attribute From(string id, PatternBuilder patternBuilder)
+ {
+ return new Attribute(new Identifier(id), patternBuilder.Build());
+ }
+
+ public bool Equals(Attribute? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Id.Equals(other.Id) && Value.Equals(other.Value);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((Attribute)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Id, Value);
+ }
}
- public class Pattern
+ public class Pattern : IEquatable
{
- public List Elements;
+ public readonly List Elements;
+
public Pattern(List elements)
{
@@ -37,18 +91,174 @@ public Pattern()
{
Elements = new List();
}
+
+ public bool Equals(Pattern? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ if (Elements.Count != other.Elements.Count)
+ {
+ return false;
+ }
+
+ for (var index = 0; index < Elements.Count; index++)
+ {
+ var patternElement = Elements[index];
+ var otherPatternElement = other.Elements[index];
+ if (!IPatternElement.PatternComparer.Equals(patternElement, otherPatternElement))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((Pattern)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return Elements.GetHashCode();
+ }
+ }
+
+ public class PatternBuilder
+ {
+ private readonly List _patternElements = new();
+
+ public PatternBuilder()
+ {
+ }
+
+ public PatternBuilder(string text)
+ {
+ _patternElements.Add(new TextLiteral(text));
+ }
+
+ public PatternBuilder(float number)
+ {
+ _patternElements.Add(new Placeable(new NumberLiteral(number)));
+ }
+
+ public PatternBuilder AddText(string textLiteral)
+ {
+ _patternElements.Add(new TextLiteral(textLiteral));
+ return this;
+ }
+
+ public PatternBuilder AddNumberLiteral(float number)
+ {
+ _patternElements.Add(new Placeable(new NumberLiteral(number)));
+ return this;
+ }
+
+ public PatternBuilder AddNumberLiteral(double number)
+ {
+ _patternElements.Add(new Placeable(new NumberLiteral(number)));
+ return this;
+ }
+
+ public PatternBuilder AddMessage(string id, string? attribute = null)
+ {
+ _patternElements.Add(new Placeable(new MessageReference(id, attribute)));
+ return this;
+ }
+
+ public PatternBuilder AddTermReference(string id, string? attribute = null, CallArguments? callArguments = null)
+ {
+ _patternElements.Add(new Placeable(new TermReference(id, attribute, callArguments)));
+ return this;
+ }
+
+ public PatternBuilder AddDynamicReference(string id, string? attribute = null,
+ CallArguments? callArguments = null)
+ {
+ _patternElements.Add(new Placeable(new DynamicReference(id, attribute, callArguments)));
+ return this;
+ }
+
+ public PatternBuilder AddFunctionReference(string functionName, CallArguments funcArgs = default)
+ {
+ _patternElements.Add(new Placeable(new FunctionReference(functionName, funcArgs)));
+ return this;
+ }
+
+ public PatternBuilder AddFunctionReference(string functionName, CallArgumentsBuilder builder)
+ {
+ _patternElements.Add(new Placeable(new FunctionReference(functionName, builder.Build())));
+ return this;
+ }
+
+ public PatternBuilder AddMessageReference(string messageId, string? attribute = null)
+ {
+ _patternElements.Add(new Placeable(new MessageReference(messageId, attribute)));
+ return this;
+ }
+
+ public PatternBuilder AddSelectExpression(SelectExpressionBuilder selectExpressionBuilder)
+ {
+ _patternElements.Add(new Placeable(selectExpressionBuilder.Build()));
+ return this;
+ }
+
+ public PatternBuilder AddExpression(IPatternElement expr)
+ {
+ _patternElements.Add(expr);
+ return this;
+ }
+
+ public PatternBuilder AddPlaceable(Placeable placeable)
+ {
+ _patternElements.Add(placeable);
+ return this;
+ }
+
+ public Pattern Build()
+ {
+ return new Pattern(_patternElements);
+ }
}
public class Identifier : IEquatable
{
+ public class IdentifierComparator : IEqualityComparer
+ {
+ public bool Equals(Identifier? x, Identifier? y)
+ {
+ if (ReferenceEquals(x, y)) return true;
+ if (ReferenceEquals(x, null)) return false;
+ if (ReferenceEquals(y, null)) return false;
+ if (x.GetType() != y.GetType()) return false;
+ return x.Name.Span.SequenceEqual(y.Name.Span);
+ }
+
+ public int GetHashCode(Identifier obj)
+ {
+ return obj.Name.GetHashCode();
+ }
+ }
+
public readonly ReadOnlyMemory Name;
+ public static readonly IdentifierComparator Comparator = new();
+
public Identifier(ReadOnlyMemory name)
{
Name = name;
}
+ public Identifier(string id)
+ {
+ Name = id.AsMemory();
+ }
+
public override string ToString()
{
return Name.Span.ToString();
@@ -58,12 +268,12 @@ public bool Equals(Identifier? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
- return ToString().Equals(other.ToString());
+ return Comparator.Equals(this, other);
}
public override int GetHashCode()
{
- return Name.GetHashCode();
+ return Comparator.GetHashCode(this);
}
}
@@ -86,23 +296,56 @@ public interface IEntry
public interface IInlineExpression : IExpression
{
+ public static readonly InlineExpressionComparer Comparer = new();
}
- public static class Base
+ public class InlineExpressionComparer : IEqualityComparer
{
+ public bool Equals(IInlineExpression? left, IInlineExpression? right)
+ {
+ return (left, right) switch
+ {
+ (DynamicReference l, DynamicReference r) => l.Equals(r),
+ (FunctionReference l, FunctionReference r) => l.Equals(r),
+ (MessageReference l, MessageReference r) => l.Equals(r),
+ (NumberLiteral l, NumberLiteral r) => l.Equals(r),
+ (Placeable l, Placeable r) => l.Equals(r),
+ (TermReference l, TermReference r) => l.Equals(r),
+ (TextLiteral l, TextLiteral r) => l.Equals(r),
+ (VariableReference l, VariableReference r) => l.Equals(r),
+ _ => false
+ };
+ }
+ public int GetHashCode(IInlineExpression obj)
+ {
+ return obj switch
+ {
+ DynamicReference dr => dr.GetHashCode(),
+ FunctionReference fr => fr.GetHashCode(),
+ MessageReference mr => mr.GetHashCode(),
+ NumberLiteral nl => nl.GetHashCode(),
+ Placeable p => p.GetHashCode(),
+ TermReference term => term.GetHashCode(),
+ TextLiteral tl => tl.GetHashCode(),
+ VariableReference vr => vr.GetHashCode(),
+ _ => throw new ArgumentOutOfRangeException(nameof(obj), obj, null)
+ };
+ }
+ }
+
+ public static class Base
+ {
public static string Stringify(this Pattern? pattern)
{
var sb = new StringBuilder();
- if (pattern != null && pattern.Elements.Count > 0)
+ if (pattern == null || pattern.Elements.Count <= 0) return sb.ToString();
+ for (var i = 0; i < pattern.Elements.Count; i++)
{
- for (var i = 0; i < pattern.Elements.Count; i++)
- {
- sb.Append(pattern.Elements[i]);
- }
+ sb.Append(pattern.Elements[i]);
}
return sb.ToString();
}
}
-}
+}
\ No newline at end of file
diff --git a/Linguini.Syntax/Ast/Entry.cs b/Linguini.Syntax/Ast/Entry.cs
index ca8ef0b..970787a 100644
--- a/Linguini.Syntax/Ast/Entry.cs
+++ b/Linguini.Syntax/Ast/Entry.cs
@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
-using System.IO;
+using System.Linq;
using System.Text;
-using Linguini.Syntax.Parser;
using Linguini.Syntax.Parser.Error;
-
namespace Linguini.Syntax.Ast
{
public record Resource
@@ -20,40 +18,65 @@ public Resource(List body, List errors)
}
}
- public class AstMessage : IEntry
+ public class AstMessage : IEntry, IEquatable
{
- public Identifier Id;
- public Pattern? Value;
- public List Attributes;
- public AstComment? Comment;
+ public readonly Identifier Id;
+ public readonly Pattern? Value;
+ public readonly List Attributes;
+
+ public AstComment? Comment => InternalComment;
+ protected internal AstComment? InternalComment;
- public AstMessage(Identifier id, Pattern? pattern, List attrs, AstComment? comment)
+ public AstMessage(Identifier id, Pattern? pattern, List attrs, AstComment? internalComment)
{
Id = id;
Value = pattern;
Attributes = attrs;
- Comment = comment;
+ InternalComment = internalComment;
}
public string GetId()
{
return Id.ToString();
}
+
+ public bool Equals(AstMessage? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Identifier.Comparator.Equals(Id, other.Id) && Equals(Value, other.Value) &&
+ Attributes.SequenceEqual(other.Attributes, Attribute.Comparer) &&
+ Equals(InternalComment, other.InternalComment);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((AstMessage)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Id, Value, Attributes, InternalComment);
+ }
}
public class AstTerm : IEntry
{
- public Identifier Id;
- public Pattern Value;
- public List Attributes;
- public AstComment? Comment;
+ public readonly Identifier Id;
+ public readonly Pattern Value;
+ public readonly List Attributes;
+ public AstComment? Comment => InternalComment;
+ protected internal AstComment? InternalComment;
public AstTerm(Identifier id, Pattern value, List attributes, AstComment? comment)
{
Id = id;
Value = value;
Attributes = attributes;
- Comment = comment;
+ InternalComment = comment;
}
@@ -63,28 +86,28 @@ public string GetId()
}
}
- public class AstComment : IEntry
+ public class AstComment : IEntry, IEquatable
{
- public CommentLevel CommentLevel;
- public readonly List> _content;
+ public readonly CommentLevel CommentLevel;
+ public readonly List> Content;
public AstComment(CommentLevel commentLevel, List> content)
{
CommentLevel = commentLevel;
- _content = content;
+ Content = content;
}
public string AsStr(string lineEnd = "\n")
{
StringBuilder sb = new();
- for (int i = 0; i < _content.Count; i++)
+ for (int i = 0; i < Content.Count; i++)
{
if (i > 0)
{
sb.Append(lineEnd);
}
- sb.Append(_content[i].Span.ToString());
+ sb.Append(Content[i].Span.ToString());
}
return sb.ToString();
@@ -94,11 +117,58 @@ public string GetId()
{
return "Comment";
}
+
+ public bool Equals(AstComment? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ if (CommentLevel != other.CommentLevel) return false;
+ if (Content.Count != other.Content.Count) return false;
+ for (int i = 0; i < Content.Count; i++)
+ {
+ var l = Content[i];
+ var r = other.Content[i];
+ if (!l.Span.SequenceEqual(r.Span))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((AstComment)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine((int)CommentLevel, Content);
+ }
}
- public class Junk : IEntry
+ public class Junk : IEntry, IEquatable
{
- public ReadOnlyMemory Content;
+ public readonly ReadOnlyMemory Content;
+
+ public Junk()
+ {
+ Content = ReadOnlyMemory.Empty;
+ }
+
+ public Junk(ReadOnlyMemory content)
+ {
+ Content = content;
+ }
+
+ public Junk(string content)
+ {
+ Content = content.AsMemory();
+ }
public string AsStr()
{
@@ -109,5 +179,25 @@ public string GetId()
{
return Content.Span.ToString();
}
+
+ public bool Equals(Junk? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Content.Span.SequenceEqual(other.Content.Span);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((Junk)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return Content.GetHashCode();
+ }
}
}
\ No newline at end of file
diff --git a/Linguini.Syntax/Ast/Expression.cs b/Linguini.Syntax/Ast/Expression.cs
index a9e1ce4..cf0024c 100644
--- a/Linguini.Syntax/Ast/Expression.cs
+++ b/Linguini.Syntax/Ast/Expression.cs
@@ -1,78 +1,182 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+// ReSharper disable UnusedMember.Global
namespace Linguini.Syntax.Ast
{
- public class TextLiteral : IInlineExpression, IPatternElement
+ public class TextLiteral : IInlineExpression, IPatternElement, IEquatable
{
- public ReadOnlyMemory Value;
+ public readonly ReadOnlyMemory Value;
public TextLiteral(ReadOnlyMemory value)
{
Value = value;
}
- public bool Equals(IPatternElement? other)
+ public TextLiteral(string id)
{
- if (other is TextLiteral textLiteralOther)
- {
- return Value.Span.SequenceEqual(textLiteralOther.Value.Span);
- }
-
- return false;
+ Value = id.AsMemory();
}
public override string ToString()
{
return Value.Span.ToString();
}
+
+ public bool Equals(TextLiteral? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Value.Span.SequenceEqual(other.Value.Span);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((TextLiteral)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
}
- public class NumberLiteral : IInlineExpression
+ public class NumberLiteral : IInlineExpression, IEquatable
{
- public ReadOnlyMemory Value;
+ public readonly ReadOnlyMemory Value;
public NumberLiteral(ReadOnlyMemory value)
{
Value = value;
}
+ public NumberLiteral(float num)
+ {
+ Value = num.ToString(CultureInfo.InvariantCulture).AsMemory();
+ }
+
+ public NumberLiteral(double num)
+ {
+ Value = num.ToString(CultureInfo.InvariantCulture).AsMemory();
+ }
+
public override string ToString()
{
return Value.Span.ToString();
}
+
+ public bool Equals(NumberLiteral? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Value.Span.SequenceEqual(other.Value.Span);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((NumberLiteral)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
}
- public class FunctionReference : IInlineExpression
+ public class FunctionReference : IInlineExpression, IEquatable
{
- public Identifier Id;
- public CallArguments Arguments;
+ public readonly Identifier Id;
+ public readonly CallArguments Arguments;
public FunctionReference(Identifier id, CallArguments arguments)
{
Id = id;
Arguments = arguments;
}
+
+ public FunctionReference(string id, CallArguments arguments)
+ {
+ Id = new Identifier(id);
+ Arguments = arguments;
+ }
+
+ public bool Equals(FunctionReference? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Id.Equals(other.Id) && Arguments.Equals(other.Arguments);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((FunctionReference)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Id, Arguments);
+ }
}
- public class MessageReference : IInlineExpression
+ public class MessageReference : IInlineExpression, IEquatable
{
- public Identifier Id;
- public Identifier? Attribute;
+ public readonly Identifier Id;
+ public readonly Identifier? Attribute;
public MessageReference(Identifier id, Identifier? attribute)
{
Id = id;
Attribute = attribute;
}
+
+ public MessageReference(string id, string? attribute = null)
+ {
+ Id = new Identifier(id);
+ if (attribute != null)
+ {
+ Attribute = new Identifier(attribute);
+ }
+ }
+
+ public bool Equals(MessageReference? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Id.Equals(other.Id) && Identifier.Comparator.Equals(Attribute, other.Attribute);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((MessageReference)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Id, Attribute);
+ }
}
- public class DynamicReference : IInlineExpression
+ public class DynamicReference : IInlineExpression, IEquatable
{
- public Identifier Id;
- public Identifier? Attribute;
- public CallArguments? Arguments;
+ public readonly Identifier Id;
+ public readonly Identifier? Attribute;
+ public readonly CallArguments? Arguments;
public DynamicReference(Identifier id, Identifier? attribute, CallArguments? arguments)
{
@@ -80,13 +184,62 @@ public DynamicReference(Identifier id, Identifier? attribute, CallArguments? arg
Attribute = attribute;
Arguments = arguments;
}
+
+ public DynamicReference(string id, string? attribute = null, CallArguments? arguments = null)
+ {
+ Id = new Identifier(id);
+ if (attribute != null)
+ {
+ Attribute = new Identifier(attribute);
+ }
+
+ if (arguments != null)
+ {
+ Arguments = arguments.Value;
+ }
+ }
+
+ public DynamicReference(string id, string? attribute, CallArgumentsBuilder? callArgumentsBuilder)
+ {
+ Id = new Identifier(id);
+ if (attribute != null)
+ {
+ Attribute = new Identifier(attribute);
+ }
+
+ if (callArgumentsBuilder != null)
+ {
+ Arguments = callArgumentsBuilder.Build();
+ }
+ }
+
+ public bool Equals(DynamicReference? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Id.Equals(other.Id) && Identifier.Comparator.Equals(Attribute, other.Attribute) &&
+ Nullable.Equals(Arguments, other.Arguments);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((DynamicReference)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Id, Attribute, Arguments);
+ }
}
-
- public class TermReference : IInlineExpression
+
+ public class TermReference : IInlineExpression, IEquatable
{
- public Identifier Id;
- public Identifier? Attribute;
- public CallArguments? Arguments;
+ public readonly Identifier Id;
+ public readonly Identifier? Attribute;
+ public readonly CallArguments? Arguments;
public TermReference(Identifier id, Identifier? attribute, CallArguments? arguments)
{
@@ -94,71 +247,410 @@ public TermReference(Identifier id, Identifier? attribute, CallArguments? argume
Attribute = attribute;
Arguments = arguments;
}
+
+ public TermReference(string id, string? attribute = null, CallArguments? arguments = null)
+ {
+ Id = new Identifier(id);
+ if (attribute != null)
+ {
+ Attribute = new Identifier(attribute);
+ }
+
+ if (arguments != null)
+ {
+ Arguments = arguments.Value;
+ }
+ }
+
+ public TermReference(string id, string? attribute, CallArgumentsBuilder? argumentsBuilder)
+ {
+ Id = new Identifier(id);
+ if (attribute != null)
+ {
+ Attribute = new Identifier(attribute);
+ }
+
+ if (argumentsBuilder != null)
+ {
+ Arguments = argumentsBuilder.Build();
+ }
+ }
+
+ public bool Equals(TermReference? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Id.Equals(other.Id) && Identifier.Comparator.Equals(Attribute, other.Attribute) &&
+ Nullable.Equals(Arguments, other.Arguments);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((TermReference)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Id, Attribute, Arguments);
+ }
}
-
- public class VariableReference : IInlineExpression
+
+ public class VariableReference : IInlineExpression, IEquatable
{
- public Identifier Id;
+ public readonly Identifier Id;
public VariableReference(Identifier id)
{
Id = id;
}
+
+ public VariableReference(string id)
+ {
+ Id = new Identifier(id);
+ }
+
+ public bool Equals(VariableReference? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Identifier.Comparator.Equals(Id , other.Id);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((VariableReference)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return Id.GetHashCode();
+ }
}
-
- public class Placeable : IInlineExpression, IPatternElementPlaceholder, IPatternElement
+
+ public class Placeable : IInlineExpression, IPatternElementPlaceholder, IPatternElement, IEquatable
{
- public IExpression Expression;
+ public readonly IExpression Expression;
public Placeable(IExpression expression)
{
Expression = expression;
}
- public bool Equals(IPatternElement? other)
+ public bool Equals(Placeable? other)
{
- if (other is Placeable otherPlaceable)
- {
- return Expression == otherPlaceable.Expression;
- }
- return false;
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Expression.Equals(other.Expression);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((Placeable)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return Expression.GetHashCode();
+ }
+ }
+
+ public class PlaceableBuilder
+ {
+ private readonly IExpression _expression;
+
+ private PlaceableBuilder(IExpression expression)
+ {
+ _expression = expression;
+ }
+
+ public static PlaceableBuilder InlineExpression(InlineExpressionBuilder inlineBuilder)
+ {
+ return new PlaceableBuilder(inlineBuilder.Build());
+ }
+
+ public static PlaceableBuilder InlineExpression(SelectExpressionBuilder selectorExpression)
+ {
+ return new PlaceableBuilder(selectorExpression.Build());
+ }
+
+ public Placeable Build()
+ {
+ return new Placeable(_expression);
}
}
-
- public struct CallArguments
+
+ public struct CallArguments : IEquatable
{
- public List PositionalArgs;
- public List NamedArgs;
+ public readonly List PositionalArgs;
+ public readonly List NamedArgs;
public CallArguments(List positionalArgs, List namedArgs)
{
PositionalArgs = positionalArgs;
NamedArgs = namedArgs;
}
+
+ public bool Equals(CallArguments other)
+ {
+ return PositionalArgs.SequenceEqual(other.PositionalArgs, IInlineExpression.Comparer)
+ && NamedArgs.SequenceEqual(other.NamedArgs);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is CallArguments other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(PositionalArgs, NamedArgs);
+ }
}
-
- public struct NamedArgument
+
+ public readonly struct NamedArgument : IEquatable
{
- public Identifier Name;
- public IInlineExpression Value;
+ public readonly Identifier Name;
+ public readonly IInlineExpression Value;
public NamedArgument(Identifier name, IInlineExpression value)
{
Name = name;
Value = value;
}
+
+ public bool Equals(NamedArgument other)
+ {
+ return Name.Equals(other.Name) && IInlineExpression.Comparer.Equals(Value, other.Value);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is NamedArgument other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Name, Value);
+ }
+ }
+
+ public class CallArgumentsBuilder
+ {
+ private readonly List _positionalArgs = new();
+ private readonly List _namedArgs = new();
+
+ public CallArgumentsBuilder AddPositionalArg(InlineExpressionBuilder arg)
+ {
+ _positionalArgs.Add(arg.Build());
+ return this;
+ }
+
+ public CallArgumentsBuilder AddPositionalArg(string text)
+ {
+ _positionalArgs.Add(new TextLiteral(text));
+ return this;
+ }
+
+ public CallArgumentsBuilder AddPositionalArg(double number)
+ {
+ _positionalArgs.Add(new NumberLiteral(number));
+ return this;
+ }
+
+ public CallArgumentsBuilder AddPositionalArg(float number)
+ {
+ _positionalArgs.Add(new NumberLiteral(number));
+ return this;
+ }
+
+ public CallArgumentsBuilder AddNamedArg(string identifier, InlineExpressionBuilder inlineExpression)
+ {
+ _namedArgs.Add(new NamedArgument(new Identifier(identifier), inlineExpression.Build()));
+ return this;
+ }
+
+ public CallArgumentsBuilder AddNamedArg(string identifier, IInlineExpression inlineExpression)
+ {
+ _namedArgs.Add(new NamedArgument(new Identifier(identifier), inlineExpression));
+ return this;
+ }
+
+ public CallArgumentsBuilder AddNamedArg(string identifier, string text)
+ {
+ _namedArgs.Add(new NamedArgument(new Identifier(identifier), new TextLiteral(text)));
+ return this;
+ }
+
+ public CallArgumentsBuilder AddNamedArg(string identifier, float number)
+ {
+ _namedArgs.Add(new NamedArgument(new Identifier(identifier), new NumberLiteral(number)));
+ return this;
+ }
+
+ public CallArgumentsBuilder AddNamedArg(string identifier, double number)
+ {
+ _namedArgs.Add(new NamedArgument(new Identifier(identifier), new NumberLiteral(number)));
+ return this;
+ }
+
+ public CallArguments Build()
+ {
+ return new CallArguments(_positionalArgs, _namedArgs);
+ }
}
-
- public class SelectExpression : IExpression
+
+ public class InlineExpressionBuilder
{
- public IInlineExpression Selector;
- public List Variants;
+ private IInlineExpression _expression;
+
+ private InlineExpressionBuilder(IInlineExpression expression)
+ {
+ _expression = expression;
+ }
+
+ public static InlineExpressionBuilder CreateDynamicReference(string id, string? attribute = null,
+ CallArgumentsBuilder? callArgumentsBuilder = null)
+ {
+ return new InlineExpressionBuilder(new DynamicReference(id, attribute, callArgumentsBuilder));
+ }
+
+ public static InlineExpressionBuilder CreateFunctionReference(string id,
+ CallArgumentsBuilder callArgumentsBuilder)
+ {
+ return new InlineExpressionBuilder(new FunctionReference(id, callArgumentsBuilder.Build()));
+ }
+
+ public static InlineExpressionBuilder CreateMessageReference(string id, string? attribute = null)
+ {
+ return new InlineExpressionBuilder(new MessageReference(id, attribute));
+ }
+
+ public static InlineExpressionBuilder CreateNumber(double numberLiteral)
+ {
+ return new InlineExpressionBuilder(new NumberLiteral(numberLiteral));
+ }
+
+ public static InlineExpressionBuilder CreateNumber(float numberLiteral)
+ {
+ return new InlineExpressionBuilder(new NumberLiteral(numberLiteral));
+ }
+
+ public static InlineExpressionBuilder CreatePlaceable(Placeable placeable)
+ {
+ return new InlineExpressionBuilder(placeable);
+ }
+
+ public static InlineExpressionBuilder CreatePlaceable(PlaceableBuilder placeable)
+ {
+ return new InlineExpressionBuilder(placeable.Build());
+ }
+
+ public static InlineExpressionBuilder CreateTermReference(string id, string? attribute = null,
+ CallArgumentsBuilder? callArgumentsBuilder = null)
+ {
+ return new InlineExpressionBuilder(new TermReference(id, attribute, callArgumentsBuilder));
+ }
+
+ public static InlineExpressionBuilder CreateTextLiteral(string textLiteral)
+ {
+ return new InlineExpressionBuilder(new TextLiteral(textLiteral));
+ }
+
+ public static InlineExpressionBuilder CreateVariableReferences(string textLiteral)
+ {
+ return new InlineExpressionBuilder(new VariableReference(textLiteral));
+ }
+
+ public IInlineExpression Build()
+ {
+ return _expression;
+ }
+ }
+
+ public class SelectExpression : IExpression, IEquatable
+ {
+ public readonly IInlineExpression Selector;
+ public readonly List Variants;
public SelectExpression(IInlineExpression selector, List variants)
{
Selector = selector;
Variants = variants;
}
+
+ public bool Equals(SelectExpression? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return IInlineExpression.Comparer.Equals(Selector, other.Selector)
+ && Variants.SequenceEqual(other.Variants);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((SelectExpression)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Selector, Variants);
+ }
+ }
+
+ public class SelectExpressionBuilder : IAddVariant
+ {
+ private readonly IInlineExpression _selector;
+ private readonly List _variants = new();
+
+ public SelectExpressionBuilder(IInlineExpression selector)
+ {
+ _selector = selector;
+ }
+
+ public IAddVariant AddVariant(string selector, PatternBuilder patternBuilder)
+ {
+ _variants.Add(new Variant(selector, patternBuilder));
+ return this;
+ }
+
+ public IAddVariant AddVariant(float selector, PatternBuilder patternBuilder)
+ {
+ _variants.Add(new Variant(selector, patternBuilder));
+ return this;
+ }
+
+ public SelectExpressionBuilder SetDefault(int? defaultSelector = null)
+ {
+ var selector = defaultSelector is >= 0 && defaultSelector < _variants.Count
+ ? _variants.Count - 1
+ : defaultSelector!.Value;
+ _variants[selector].InternalDefault = true;
+ return this;
+ }
+
+ public SelectExpression Build()
+ {
+ return new SelectExpression(_selector, _variants);
+ }
+ }
+
+ public interface IAddVariant
+ {
+ public IAddVariant AddVariant(string selector, PatternBuilder patternBuilder);
+ public IAddVariant AddVariant(float selector, PatternBuilder patternBuilder);
+ public SelectExpressionBuilder SetDefault(int? defaultSelector = null);
}
public enum VariantType : byte
@@ -168,19 +660,68 @@ public enum VariantType : byte
}
- public class Variant
+ public class Variant : IEquatable
{
- public VariantType Type;
- public ReadOnlyMemory Key;
- public Pattern Value;
- public bool IsDefault;
+ public readonly VariantType Type;
+ public readonly ReadOnlyMemory Key;
+ public Pattern Value => InternalValue;
+ public bool IsDefault => InternalDefault;
+
+ protected internal bool InternalDefault;
+ protected internal Pattern InternalValue;
public Variant(VariantType type, ReadOnlyMemory key)
{
Type = type;
Key = key;
- Value = new Pattern();
- IsDefault = false;
+ InternalValue = new Pattern();
+ InternalDefault = false;
+ }
+
+ public Variant(VariantType type, ReadOnlyMemory key, Pattern pattern, bool isDefault = false)
+ {
+ Type = type;
+ Key = key;
+ InternalValue = pattern;
+ InternalDefault = isDefault;
+ }
+
+ public Variant(string key, PatternBuilder builder)
+ {
+ Type = VariantType.Identifier;
+ Key = key.AsMemory();
+ InternalValue = builder.Build();
+ InternalDefault = false;
+ }
+
+ public Variant(float key, PatternBuilder builder)
+ {
+ Type = VariantType.NumberLiteral;
+ Key = key.ToString(CultureInfo.InvariantCulture).AsMemory();
+ InternalValue = builder.Build();
+ InternalDefault = false;
+ }
+
+ public bool Equals(Variant? other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return Type == other.Type && Key.Span.SequenceEqual(other.Key.Span) &&
+ InternalDefault == other.InternalDefault &&
+ InternalValue.Equals(other.InternalValue);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((Variant)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine((int)Type, Key, InternalDefault, InternalValue);
}
}
}
\ No newline at end of file
diff --git a/Linguini.Syntax/Ast/Pattern.cs b/Linguini.Syntax/Ast/Pattern.cs
index 54a7a5b..abbc9cb 100644
--- a/Linguini.Syntax/Ast/Pattern.cs
+++ b/Linguini.Syntax/Ast/Pattern.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Linguini.Syntax.Ast
@@ -29,8 +30,35 @@ public interface IPatternElementPlaceholder
{
}
- public interface IPatternElement: IEquatable
- {
+ public interface IPatternElement
+ {
+ public static PatternComparer PatternComparer = new();
+ }
+
+ public class PatternComparer : IEqualityComparer
+ {
+ public bool Equals(IPatternElement? left, IPatternElement? right)
+ {
+ return (left, right) switch
+ {
+ (TextLiteral l, TextLiteral r) => l.Equals(r),
+ (Placeable l, Placeable r) => l.Equals(r),
+ _ => false,
+ };
+ }
+
+ public int GetHashCode(IPatternElement obj)
+ {
+ switch (obj)
+ {
+ case TextLiteral textLiteral:
+ return textLiteral.GetHashCode();
+ case Placeable placeable:
+ return placeable.GetHashCode();
+ default:
+ throw new ArgumentException("Unexpected type", nameof(obj));
+ }
+ }
}
public class TextElementPlaceholder : IPatternElementPlaceholder
diff --git a/Linguini.Syntax/Linguini.Syntax.csproj b/Linguini.Syntax/Linguini.Syntax.csproj
index 27903c9..92df86e 100644
--- a/Linguini.Syntax/Linguini.Syntax.csproj
+++ b/Linguini.Syntax/Linguini.Syntax.csproj
@@ -12,7 +12,7 @@
https://github.com/Ygg01/Linguini
git
net6.0;netstandard2.1;net8.0
- 0.7.0
+ 0.8.0
README.md
linguini.jpg
diff --git a/Linguini.Syntax/Parser/LinguiniParser.cs b/Linguini.Syntax/Parser/LinguiniParser.cs
index 7c7093e..91f973a 100644
--- a/Linguini.Syntax/Parser/LinguiniParser.cs
+++ b/Linguini.Syntax/Parser/LinguiniParser.cs
@@ -1,5 +1,4 @@
-
-using System;
+using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
@@ -142,12 +141,12 @@ public Resource ParseWithComments()
if (entry is AstMessage message
&& lastBlankCount < 2)
{
- message.Comment = lastComment;
+ message.InternalComment = lastComment;
}
else if (entry is AstTerm term
&& lastBlankCount < 2)
{
- term.Comment = lastComment;
+ term.InternalComment = lastComment;
}
else
{
@@ -187,9 +186,9 @@ private void AddError(ParseError error, int entryStart, List errors,
_reader.SkipToNextEntry();
error.Slice = new Range(entryStart, _reader.Position);
errors.Add(error);
- Junk junk = new();
+
var contentSpan = _reader.ReadSlice(entryStart, _reader.Position);
- junk.Content = contentSpan;
+ Junk junk = new(contentSpan);
body.Add(junk);
}
@@ -947,8 +946,8 @@ private bool TryGetVariants(out List variants, out ParseError? error)
if (value != null)
{
- variant.Value = value;
- variant.IsDefault = isDefault;
+ variant.InternalValue = value;
+ variant.InternalDefault = isDefault;
variants.Add(variant);
_reader.SkipBlank();
}
diff --git a/Linguini.sln b/Linguini.sln
index c43d808..201f10d 100644
--- a/Linguini.sln
+++ b/Linguini.sln
@@ -18,6 +18,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Linguini.Serialization", "L
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Linguini.Bench", "Linguini.Bench\Linguini.Bench.csproj", "{464CC3E4-7259-4840-B342-B346F3533CED}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Linguini.Serialization.Test", "Linguini.Serialization.Test\Linguini.Serialization.Test.csproj", "{32A38C1D-CA5E-41DA-8FCB-07551D35D382}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -64,5 +66,9 @@ Global
{464CC3E4-7259-4840-B342-B346F3533CED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{464CC3E4-7259-4840-B342-B346F3533CED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{464CC3E4-7259-4840-B342-B346F3533CED}.Release|Any CPU.Build.0 = Release|Any CPU
+ {32A38C1D-CA5E-41DA-8FCB-07551D35D382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {32A38C1D-CA5E-41DA-8FCB-07551D35D382}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {32A38C1D-CA5E-41DA-8FCB-07551D35D382}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {32A38C1D-CA5E-41DA-8FCB-07551D35D382}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/PluralRules.Generator/PluralRules.Generator.csproj b/PluralRules.Generator/PluralRules.Generator.csproj
index 3dbbc12..dc6ed6b 100644
--- a/PluralRules.Generator/PluralRules.Generator.csproj
+++ b/PluralRules.Generator/PluralRules.Generator.csproj
@@ -10,6 +10,7 @@
README.md
linguini.jpg
sourcegen, plural rules, icu
+ 0.8.0
diff --git a/PluralRules.Test/Cldr/CldrParserTest.cs b/PluralRules.Test/Cldr/CldrParserTest.cs
index 3b3c28b..7339254 100644
--- a/PluralRules.Test/Cldr/CldrParserTest.cs
+++ b/PluralRules.Test/Cldr/CldrParserTest.cs
@@ -60,8 +60,8 @@ public void ParseEmpty()
[Parallelizable]
[TestCase("n is 12 @integer 0, 5, 7~20", new[] {"0", "5", "7~20"}, new string[] { })]
[TestCase("n is 12 @integer 0, 5, 7~20 @decimal 1, 3~6,...", new[] {"0", "5", "7~20"},
- new string[] {"1", "3~6"})]
- [TestCase("@integer 0, 11~25, 100, 1000, …", new string[] {"0", "11~25", "100", "1000"}, new string[] { })]
+ new[] {"1", "3~6"})]
+ [TestCase("@integer 0, 11~25, 100, 1000, …", new[] {"0", "11~25", "100", "1000"}, new string[] { })]
public void ParseSamples(string input, string[] expIntRangeList, string[] expDecRangeList)
{
var rule = new CldrParser(input).ParseRule();
diff --git a/PluralRules.Test/PluralRules.Test.csproj b/PluralRules.Test/PluralRules.Test.csproj
index 5499de4..734a65e 100644
--- a/PluralRules.Test/PluralRules.Test.csproj
+++ b/PluralRules.Test/PluralRules.Test.csproj
@@ -6,6 +6,7 @@
PluralRules.Test
Library
net6.0
+ 0.8.0