DでHTML MPL編

01:59 (s***) コンパイル時に可能な限り静的な文字列にしてくれたりすると萌え萌え

そのねがいかなえてしんぜよー。

const bool inline = true;

template Tag(char[] name, bool isInline = false){
    template Param(
        char[] p0,
        char[] p1 = "",
        char[] p2 = ""
    ){
        static if (p0.length == 0)
            const char[] attr = "";
        else static if (p1.length == 0)
            const char[] attr = set!(p0);
        else static if (p2.length == 0)
            const char[] attr = set!(p0) ~ set!(p1);
        else
            const char[] attr = set!(p0) ~ set!(p1) ~ set!(p2);

        template Text(char[] str = ""){
            static if (isInline)
                const char[] Text = "<" ~ name ~ attr ~ ">" ~ str ~ "</" ~ name ~ ">\n";
            else
                const char[] Text = "<" ~ name ~ attr ~ ">\n" ~ nest!(str) ~ "</" ~ name ~ ">\n";
        }
    }

    template Text(char[] str = ""){
        static if (isInline)
            const char[] Text = "<" ~ name ~ ">" ~ str ~ "</" ~ name ~ ">\n";
        else
            const char[] Text = "<" ~ name ~ ">\n" ~ nest!(str) ~ "</" ~ name ~ ">\n";
    }
}

template nest(char[] s, int i = 0){
    static if (s.length == 0){
        const char[] nest = "";
    } else static if (s.length-1 == i){
        static if (s[i] == '\n'){
            const char[] nest = s;
        } else {
            const char[] nest = s ~ '\n';
        }
    } else static if (i == 0){
        const char[] nest = nest!("    " ~ s, i+5);
    } else static if (s[i] == '\n'){
        const char[] nest = nest!(s[0 .. i+1] ~ "    " ~ s[i+1 .. length], i+5);
    } else {
        const char[] nest = nest!(s, i+1);
    }
}

template set(char[] s, int i = 0){
    static if (s[i] == '=')
        const char[] set = ' ' ~ s[0 .. i] ~ "=\"" ~ s[i+1 .. length] ~ '"';
    else static if (s.length-1 == i)
        const char[] set = ' ' ~ s;
    else
        const char[] set = set!(s, i+1);
}

alias Tag!("html") html;
alias Tag!("head") head;
alias Tag!("title", inline) title;
alias Tag!("body") body_;
alias Tag!("H1", inline) H1;

void main(){
    char[] s =
    html.Text!(
        head.Text!(
            title.Text!("test") ~
            body_.Text!(
                H1.Text!("hoge") ~
                H1.Param!("color=red", "size=3").Text!("hige")
            )
        )
    );
    printf("%.*s", s);
}

だいぶ病んだコードに見えます。出力。

<html>
    <head>
        <title>test</title>
        <body>
            <H1>hoge</H1>
            <H1 color="red" size="3">hige</H1>
        </body>
    </head>
</html>

ちゃんと動きます。
なんとか「.Text!」を書かなくてもいいように出来ないかなあと思ったんですが、ボクには知恵が足りませんでした。
最近面倒くさいというだけで「import std.c.stdio;」書かなくなってしまったんですが、悪い兆候な気がします…
あと、疑り深いボクは「ほんとにコンパイル時定数になってるのか?」と思い(自分が信じられない年頃)、実行形式を直接バイナリで見るという荒業を試みました。
なってるにはなってるようなのですが、何故か複数同じ物が埋め込まれてるみたいで、これどういう理由でこうなってるのかなあと思ったりしました。謎。