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."; 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 translator = new PoyoLangTranslator();
var translated = translator.TranslateToPoyo(text); 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 var formattedDictionaries = parsedDictionaries
.Select(static (dictionary, _) => .Select(static (dictionary, _) =>
{ {
// Reverse dictionary order to have ngrams first // Return normal and reverse dictionary order to have ngrams first
return dictionary!.OrderBy(p => p.Value).ToDictionary(p => p.Value, p => p.Key); return (
Normal: dictionary,
Reversed: dictionary!.OrderBy(p => p.Value).ToDictionary(p => p.Value, p => p.Key)
);
}); });
var prefixTrees = formattedDictionaries 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(); var source = new StringBuilder();
@@ -128,43 +134,9 @@ public class PoyoLangTranslatorGenerator : IIncrementalGenerator
""" """
); );
// Next letter method definition GenerateNextLetterMethod(rootNodes, source);
source.Append(
"""
private void NextLetter(ref ReadOnlySpan<char> text, StringBuilder output)
{
"""
);
// 0 length case and caps GenerateFromPoyoMethod(dictionary, source);
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..];
}
"""
);
// Partial class end // Partial class end
source.Append( source.Append(
@@ -176,78 +148,224 @@ public class PoyoLangTranslatorGenerator : IIncrementalGenerator
return source.ToString(); 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); // Next letter method definition
// Switch-case start
source.Append( source.Append(
$$""" """
{{indent}}switch (text[{{depth}}]) private void NextLetter(ref ReadOnlySpan<char> text, StringBuilder output)
{{indent}}{ {
"""
);
// 0 length case and caps
source.Append(
"""
if (text.Length < 1)
{
return;
}
var isCaps = char.IsUpper(text[0]);
""" """
); );
foreach (var node in nodes) GenerateSwitchCases(rootNodes, depth: 0);
{
var targetLower = node.Target;
var targetUpper = ToTitleCase(targetLower);
// 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( source.Append(
$$""" $$"""
{{indent}} case '{{node.Letter}}' or '{{char.ToUpper(node.Letter)}}': {{indent}}switch (text[{{depth}}])
{{indent}}{
""" """
); );
// Sub nodes handling foreach (var node in nodes)
if (node.Nodes.Count > 0)
{ {
var targetLower = node.Target;
var targetUpper = ToTitleCase(targetLower);
// Case start
source.Append( source.Append(
$$""" $$"""
{{indent}} if (text.Length > {{depth + 1}}) {{indent}} case '{{node.Letter}}' or '{{char.ToUpper(node.Letter)}}':
{{indent}} {
""" """
); );
// Sub nodes // Sub nodes handling
GenerateSwitchCases(node.Nodes, depth + 1, source); 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( 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( source.Append(
$$""" $$"""
{{indent}} {{indent}}}
{{indent}} text = text[{{depth + 1}}..];
{{indent}}
{{indent}} output.Append(isCaps ? "{{targetUpper}}" : "{{targetLower}}");
{{indent}}
{{indent}} return;
""" """
); );
} }
}
// Switch-case end private static void GenerateFromPoyoMethod(Dictionary<string, string> dictionary, StringBuilder source)
{
// From Poyo method definition
source.Append( 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) private static string ToTitleCase(string text)

View File

@@ -21,4 +21,19 @@ public partial class PoyoLangTranslator
return output.ToString(); 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();
}
} }