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.";
|
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);
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user