Add translator from poyo
This commit is contained in:
@@ -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);
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user