Add translator from poyo

This commit is contained in:
2025-05-16 14:07:02 +02:00
parent f83f59c05a
commit f39d936024
3 changed files with 219 additions and 75 deletions

View File

@@ -7,8 +7,19 @@ Console.OutputEncoding = Encoding.UTF8;
var text = "Immutable abstract representation of a span of text. For example, in an error diagnostic that reports a location, it could come from a parsed string, text from a tool editor buffer, etc.";
Console.WriteLine("Original:");
Console.WriteLine(text);
Console.WriteLine();
var translator = new PoyoLangTranslator();
var translated = translator.TranslateToPoyo(text);
Console.WriteLine(translated);
Console.WriteLine("Translated to Poyo:");
Console.WriteLine(translated);
Console.WriteLine();
var original = translator.TranslateFromPoyo(translated);
Console.WriteLine("Translated back from Poyo:");
Console.WriteLine(original);

View File

@@ -26,16 +26,22 @@ public class PoyoLangTranslatorGenerator : IIncrementalGenerator
var formattedDictionaries = parsedDictionaries
.Select(static (dictionary, _) =>
{
// Reverse dictionary order to have ngrams first
return dictionary!.OrderBy(p => p.Value).ToDictionary(p => p.Value, p => p.Key);
// Return normal and reverse dictionary order to have ngrams first
return (
Normal: dictionary,
Reversed: dictionary!.OrderBy(p => p.Value).ToDictionary(p => p.Value, p => p.Key)
);
});
var prefixTrees = formattedDictionaries
.Select(static (formattedDictionary, _) => BuildPrefixTree(formattedDictionary));
.Select(static (dictionaries, _) => (
Dictionary: dictionaries.Normal,
PrefixTree: BuildPrefixTree(dictionaries.Reversed)
));
context.RegisterSourceOutput(prefixTrees, static (sourceProductionContext, prefixTree) =>
context.RegisterSourceOutput(prefixTrees, static (sourceProductionContext, data) =>
{
sourceProductionContext.AddSource("PoyoLangTranslator.g.cs", GenerateSource(prefixTree));
sourceProductionContext.AddSource("PoyoLangTranslator.g.cs", GenerateSource(data.Dictionary, data.PrefixTree));
});
}
@@ -103,7 +109,7 @@ public class PoyoLangTranslatorGenerator : IIncrementalGenerator
}
}
private static string GenerateSource(List<Node> rootNodes)
private static string GenerateSource(Dictionary<string, string> dictionary, List<Node> rootNodes)
{
var source = new StringBuilder();
@@ -128,43 +134,9 @@ public class PoyoLangTranslatorGenerator : IIncrementalGenerator
"""
);
// Next letter method definition
source.Append(
"""
private void NextLetter(ref ReadOnlySpan<char> text, StringBuilder output)
{
"""
);
GenerateNextLetterMethod(rootNodes, source);
// 0 length case and caps
source.Append(
"""
if (text.Length < 1)
{
return;
}
var isCaps = char.IsUpper(text[0]);
"""
);
GenerateSwitchCases(rootNodes, depth: 0, source: source);
// Next letter method end
source.Append(
"""
// Punctuation/Unknown characters case
output.Append(text[0]);
text = text[1..];
}
"""
);
GenerateFromPoyoMethod(dictionary, source);
// Partial class end
source.Append(
@@ -176,78 +148,224 @@ public class PoyoLangTranslatorGenerator : IIncrementalGenerator
return source.ToString();
}
private static void GenerateSwitchCases(List<Node> nodes, int depth, StringBuilder source)
private static void GenerateNextLetterMethod(List<Node> rootNodes, StringBuilder source)
{
var indent = Indent(depth * 3);
// Switch-case start
// Next letter method definition
source.Append(
$$"""
{{indent}}switch (text[{{depth}}])
{{indent}}{
"""
private void NextLetter(ref ReadOnlySpan<char> text, StringBuilder output)
{
"""
);
// 0 length case and caps
source.Append(
"""
if (text.Length < 1)
{
return;
}
var isCaps = char.IsUpper(text[0]);
"""
);
foreach (var node in nodes)
{
var targetLower = node.Target;
var targetUpper = ToTitleCase(targetLower);
GenerateSwitchCases(rootNodes, depth: 0);
// Case start
// Next letter method end
source.Append(
"""
// Punctuation/Unknown characters case
output.Append(text[0]);
text = text[1..];
}
"""
);
return;
void GenerateSwitchCases(List<Node> nodes, int depth)
{
var indent = Indent(depth * 3);
// Switch-case start
source.Append(
$$"""
{{indent}} case '{{node.Letter}}' or '{{char.ToUpper(node.Letter)}}':
{{indent}}switch (text[{{depth}}])
{{indent}}{
"""
);
// Sub nodes handling
if (node.Nodes.Count > 0)
foreach (var node in nodes)
{
var targetLower = node.Target;
var targetUpper = ToTitleCase(targetLower);
// Case start
source.Append(
$$"""
{{indent}} if (text.Length > {{depth + 1}})
{{indent}} {
{{indent}} case '{{node.Letter}}' or '{{char.ToUpper(node.Letter)}}':
"""
);
// Sub nodes
GenerateSwitchCases(node.Nodes, depth + 1, source);
// Sub nodes handling
if (node.Nodes.Count > 0)
{
source.Append(
$$"""
{{indent}} if (text.Length > {{depth + 1}})
{{indent}} {
"""
);
// Sub nodes
GenerateSwitchCases(node.Nodes, depth + 1);
source.Append(
$$"""
{{indent}} }
"""
);
}
// Current node handling fallback
source.Append(
$$"""
{{indent}} }
{{indent}}
{{indent}} text = text[{{depth + 1}}..];
{{indent}}
{{indent}} output.Append(isCaps ? "{{targetUpper}}" : "{{targetLower}}");
{{indent}}
{{indent}} return;
"""
);
}
// Current node handling fallback
// Switch-case end
source.Append(
$$"""
{{indent}}
{{indent}} text = text[{{depth + 1}}..];
{{indent}}
{{indent}} output.Append(isCaps ? "{{targetUpper}}" : "{{targetLower}}");
{{indent}}
{{indent}} return;
{{indent}}}
"""
);
}
}
// Switch-case end
private static void GenerateFromPoyoMethod(Dictionary<string, string> dictionary, StringBuilder source)
{
// From Poyo method definition
source.Append(
$$"""
{{indent}}}
"""
private void FromPoyo(ref ReadOnlySpan<char> text, StringBuilder output)
{
"""
"""
);
// Initial cases
source.Append(
"""
if (text.Length < 1)
{
return;
}
// This happens if the end of the text is not a poyo letter (punctuation for ex)
if (text.Length < 4)
{
output.Append(text);
text = text[^0..];
return;
}
var letter = text[..4];
"""
);
GenerateReverseSwitchCases();
// From Poyo method end
source.Append(
"""
// Advance in text
text = text[4..];
}
"""
);
return;
void GenerateReverseSwitchCases()
{
// Switch start
source.Append(
"""
switch (letter)
{
"""
);
foreach (var pair in dictionary)
{
// Non-caps case
source.Append(
$$"""
case "{{pair.Key}}":
output.Append("{{pair.Value}}");
break;
"""
);
// Caps case
source.Append(
$$"""
case "{{ToTitleCase(pair.Key)}}":
output.Append("{{ToTitleCase(pair.Value)}}");
break;
"""
);
}
// Switch end
source.Append(
"""
default:
// Not a poyo letter, only read 1 character (could be punctuation for ex)
output.Append(text[0]);
text = text[1..];
return;
}
"""
);
}
}
private static string ToTitleCase(string text)

View File

@@ -21,4 +21,19 @@ public partial class PoyoLangTranslator
return output.ToString();
}
public string TranslateFromPoyo(ReadOnlySpan<char> text)
{
var output = new StringBuilder(text.Length);
while (text.Length > 0)
{
// Skip spaces (those are not used in this language)
text = text.TrimStart(' ');
FromPoyo(ref text, output);
}
return output.ToString();
}
}