🧠
業務中に 難解プログラミング言語をC#から呼びたいときに使うライブラリを作ったよ!(そんな業務あってたまるか!)
皆さん、難解プログラミング言語(Esolang) って知っておりますでしょうか?
有名なのだと、 Brainfuck の様な 意図的に読解が困難なように設計されたプログラミング言語 のことです。
で本題
で、 まず、 C# には source generator を使って 未実装な partial な関数を実装するアプローチがよくあります。
標準の ILogger を使った ゼロアロケートロギングとかも
// LogInformation() の第二引数以降は params object[] args なので 構造体を入れると boxing する
log.LogInformation("{value}", value);
var log_ = new Log(log);
log_.LogValue(value);
partial class Log(ILogger log) {
[LoggerMessage(LogLevel.Infomration, "{value}")]
public partial void LogValue(int value);
}
とかすることで Log.LogValue() の実装が追加されます。
なので、私は「難解プログラミング言語」を 関数として実装しようと思います。
え、なんて?
そうです、 ソースジェネレータで 難解プログラミング言語を関数化します。
で、ここに作成したライブラリがあります。
使い方
とりあえず プロジェクトを作ります
dotnet new console -n EsolangSample
cd EsolangSample
dotnet add package Esolang.Brainfuck.Generator
dotnet add package Esolang.Piet.Generator
dotnet add package Esolang.Funge.Generator
して これでいけますね。
using Esolang.Brainfuck;
using Esolang.Funge;
using Esolang.Piet;
Console.WriteLine(Programs.BrainfuckHelloWorld());
Console.WriteLine(Programs.FungeHelloWorld());
Console.WriteLine(Programs.PietHelloWorld());
partial class Programs
{
[GenerateBrainfuckMethod("1+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.")]
public static partial string BrainfuckHelloWorld();
[GeneratePietMethod("data:text/ascii-piet,nqiaecfbknmeRtakcsqimemerTcnjlvutqiavtFsvubntqcslnqBbjemu udjiNqifu r tlaFvldq rrr vneVujbm k nmsRsnadv a vfkqSkdceumbmuqcrVqesqfnbsrvtjUnfcltltdljceMkcltuemnbfnkB")]
public static partial string PietHelloWorld();
[GenerateFungeMethod( InlineSource ="""
> v
v ,,,,,"Hello" <
>48*, v
v,,,,,,"World!" <
>25*,@
""")]
public static partial string FungeHelloWorld();
}
とりあえず Program.cs 単体で完結できる方法なので他の方法についてはあとで解説しますが
brainfuck は 見ての通り、
piet は 仮に ascii-piet 構文で、
funge は raw string リテラルで
記述しています。
別の指定方法
プロジェクトに sample というフォルダを作って
sample/hello.b98
64+"!dlroW ,olleH">:#,_@
sample/hw1-11.gif

EsolangSample.csproj に次の ItemGroup を追加します。
<ItemGroup>
<FungeSource Include="sample\*.b98" />
<PietImage Include="sample\hw1-11.gif" CodelSize="11" PietLogicalPath="hw1-11.gif" />
</ItemGroup>
そして先ほどの Programs クラスに次のメソッドを追加します。
[GeneratePietMethod("hw1-11.gif")]
public static partial string PietHelloWorld2();
[GenerateFungeMethod("sample/hello.b98")]
public static partial string FugneHelloWorld2();
これにより画像やファイルからメソッドが作れます。
以上!
欄外:技術的な話: ソースジェネレータは text ファイルしか読み込めないのでは……?
そうです。だめです。ソースジェネレータのフェイズではだめです。なのでこっちではビルドフェイズに画像をテキストに変換しています。
なのででっかい画像ファイルとかだと凄く不利です。
以上!
作成物
Discussion
Brainfuckは言語の仕様として
この辺厳密に決まっていないところがあったりするので処理系や既存コードで問題になることがありますがその辺自由に設定できるようなれば紹介されてるライブラリも業務で利用される機会が増える気がしますがどうでしょうか。
特に設定項目は無いですが、生成時に使っている 属性にそういう項目を設けることで挙動を切り替えたりするのも手ですね。