やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

IndentedTextWriterでソースコードを生成してみる

 思い通りのソースコードができた。

成果物

前回まで

IndentedTextWriter

dotnet new console -o IndentWrite
cd IndentWrite
dotnet add package System.CodeDom

Program.cs

namespace IndentWrite
{
    class Program
    {
        static void Main(string[] args)
        {
            new Generator().Run();
        }
    }
}

Generator.cs

using System;
using System.IO;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace IndentWrite
{
    class Generator
    {
        // in/out/ref付きのものはFunc,Actionにないためdelegate定義必須
        // https://teratail.com/questions/66340
        private delegate void CreateCodeDelegate(in IndentedTextWriter tw);
        public void Run()
        {
            Generate(CreateCode);
        }
        // ファイル出力
        private void Generate(CreateCodeDelegate createCode)
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            string sourceFile = @"Hello.cs";
            using (StreamWriter sw = new StreamWriter(sourceFile, false))
            {
                IndentedTextWriter tw = new IndentedTextWriter(sw, "    ");
                createCode(tw);
                tw.Close();
            }
        }
        // コード生成
        public void CreateCode(in IndentedTextWriter tw)
        {
            tw.WriteLine("using System;");
            tw.WriteLine();
            tw.WriteLine("namespace MyNamespace");
            tw.WriteLine("{");
            tw.Indent++;
            tw.WriteLine("public sealed class MyClass");
            tw.WriteLine("{");
            tw.Indent++;
            tw.WriteLine("static void Main(string[] args)");
            tw.WriteLine("{");
            tw.Indent++;
            tw.WriteLine(@"Console.WriteLine(""Hello world"");");
            tw.Indent--;
            tw.WriteLine("}");
            tw.Indent--;
            tw.WriteLine("}");
            tw.Indent--;
            tw.WriteLine("}");
        }
    }
}

出力結果

dotnet run

Hello.cs

using System;

namespace MyNamespace
{
    public sealed class MyClass
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello world");
        }
    }
}

 そう、これが欲しかった。

所感

 コード生成が頭悪そう。ポイントはtw.Indent。インデントを適時適切に指定せねばならない。なので文字列を一気に結合するわけにはいかないのが辛い。

 IndentedTextWriterのためにdotnet add package System.CodeDomせねばならないのは嫌だ。類似コードを自作したい。

 ツリー構造はNode.Add(Node);のようにすれば良さそう。ブロック文字{の前後にある改行も指定できるようにしたい。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux