/* faceFuck2D version 1.2
 * Copyright (C) 2008 mgen and Ge0rG (#D on freenode)
 *
 * This code is under the Public Domain.
 */
const char[] hello_world = r":) :) :) :) :) :) :) :) :) :) 
=( 
:> :) :) :) :) :) :) :) :> :) :) :) :) :) :) :) :) :) :) :> :) :) :) :> :) :< :< :< :< :( 
=) 
:> :) :) :P 
:> :) :P 
:) :) :) :) :) :) :) :P 
:P 
:) :) :) :P 
:> :) :) :P 
:< :< :) :) :) :) :) :) :) :) :) :) :) :) :) :) :) :P 
:> :P 
:) :) :) :P 
:( :( :( :( :( :( :P 
:( :( :( :( :( :( :( :( :P 
:> :) :P 
:> :P 
";

const char[] cat = ":D :) =( :( :P :D :) =)";

version(Tango)
{
    import tango.io.Stdout;
    import tango.stdc.stdio;
}
version(Phobos)
{
    import std.c.stdio;
}

//IMPORTANT, INCLUDE THIS IN YOUR PROGRAM, IMPORTS ARE NOT ALLOWED AFTER CTFE
    version(Tango)
    {
        import tango.stdc.stdio;
    }
    version(Phobos)
    {
        import std.c.stdio;
    }
//END

char[] faceFuckToD(in char[] source,char[] results = "")
{
    const char[] resultHeader = r"/*FaceFuck 1.0*/
    
    delegate void() {
    
    ubyte[] data = [0];
    uint pointer = 0;
    ";

    uint l = 0;
    while(l < source.length)
    {
        switch(source[l++])
        {
            case '>':
            case '<':
                break;
            case ':':
                //assert(false,"found ':'");
                switch(source[l++])
                {
                    case '>':
                        //assert(false,"found ':>'");
                        results ~= r"
                            pointer++;
                            if(pointer >= data.length) {
                                data ~= 0;
                            }
                        ";
                        continue;
                    case '<':
                        //assert(false,"found ':<'");
                        results ~= r"
                            if(pointer != 0) pointer--;
                        ";
                        continue;
                    case ')':
                        //assert(false,"found ':)'");
                        results ~= r"
                            data[pointer]++;
                        ";
                        continue;
                    case '(':
                        //assert(false,"found ':('");
                        results ~= r"
                            data[pointer]--;
                        ";
                        continue;
                    case 'P':
                        //assert(false,"found ':P'");
                        results ~= r"
                            putchar(cast(char)data[pointer]);
                        ";
                        continue;
                    case 'D':
                        //assert(false,"found ':D'");
                        results ~= r"
                            data[pointer] = cast(ubyte)getchar();
                        ";
                        continue;
                    default:
                        break;
                }
                break;
            case '^':
            case ';':
            case '@':
            case 'O':
            case 'o':
                break;
            case '=':
                switch(source[l++])
                {
                    case '(':
                        //assert(false,"found '=('");
                        results ~= r"
                            while(data[pointer])
                            {
                        ";
                        continue;
                    case ')':
                        //assert(false,"found '=)'");
                        results ~= r"
                                };
                        ";
                        continue;
                    default:
                        break;
                }
                break;
            default:
                break;
        }
    }
    return resultHeader~results~"}\n";
}

void main()
{
    //Stdout(faceFuckToD(hello_world)).newline;
    auto hellofunc = mixin(faceFuckToD(hello_world));
    hellofunc();
}
