Apache "mod_d" needs C to instantiate D interpreter?

Adam Ruppe destructionator at gmail.com
Wed Nov 10 06:03:56 PST 2010


Eric Poggel wrote:
> Are there any web-friendly languages that are mature, offer the sanity and
> static typing of C#, and the "immediate mode" of php?


We could do it in D, somewhat easily. Here's an implementation with only mild
bugginess:

===

import std.file;
import std.string;
import std.stdio;
import std.process;

void main(string[] args) {
        string imports = q{
                import std.stdio;
                import std.string;
                import std.file;
                import std.conv;
                import std.algorithm;
                import std.date;
        };

        string mainf = `void main(string[] args) {`;

        bool inD = false;

        string currentLiteral = "";

        string currentPrinter = "";

        void addToCurrentLiteral(string s) {
                currentLiteral ~= s.replace("`", "`~\"`\"~`");
        }

        void outputCurrentLiteral() {
                if(currentLiteral.length == 0)
                        return;

                mainf ~= "writef(\"%s\", `"~currentLiteral~"`);";

                currentLiteral.length = 0;
        }

        void appendCode(string line) {
                outputCurrentLiteral;
                if(line.length > 6 && line[0..6] == "import")
                        imports ~= line;
                else
                        mainf ~= line;
        }

        foreach(ln; stdin.byLine) {
                string line = ln.idup ~ "\n";
          modeSwitch:
                if(line.length == 0)
                        continue;
                if(!inD) {
                        int idx = line.indexOf("<?");
                        if(idx == -1) {
                                addToCurrentLiteral(line);
                        } else {
                                char c = line[idx+2];
                                switch(c) {
                                        case 'd':
                                                addToCurrentLiteral(line[0..idx]);
                                                inD = true;
                                                line = line[idx + 3 .. $];
                                                goto modeSwitch;
                                        break;
                                        case '=':
                                                addToCurrentLiteral(line[0..idx]);

                                                int end =
line[idx+2..$].indexOf("?>");
                                                if(end == -1) throw new
Exception("<?= ?> must be on one line");
                                                end += idx + 2;

                                                outputCurrentLiteral;

                                                mainf ~= `writef("%s",
`~line[idx+3..end].replace(`"`, `\"`)~`);`;

                                                line = line[end+2..$];
                                                goto modeSwitch;
                                        break;
                                        default:
                                                addToCurrentLiteral(line);
                                }
                        }
                } else {
                        int idx = line.indexOf("?>");

                        if(idx == -1) {
                                appendCode(line);
                        } else {
                                appendCode(line[0..idx]);
                                line = line[idx+2..$];
                                inD = false;
                                goto modeSwitch;
                        }
                }
        }

        outputCurrentLiteral;

        mainf ~= `}`;

        std.file.write("/tmp/tempdprog.d", imports ~ mainf);

        system("dmd -run /tmp/tempdprog.d");
}

===


Here's an example of use:

======

$ cat test.dhp
hello world
<?d auto eat = "eat me!"; ?>
this is awful
<?=eat?>
<?d
        string functionsWorkToo() {
                return "because nested functions rock!";
        }

        writeln(functionsWorkToo());
?>
Bye!

=======

And running it:

======
$ cat test.dhp | ./dhp
hello world

this is awful
eat me!
because nested functions rock!

Bye!
========



Of course, you'll want to add an automatic import for a cgi module so that's
available, and change the writefs to cgi.outs or whatever, but that's easy. (You
could use mine: http://arsdnet.net/dcode/cgi.d or your own)

The big bug I know of is if the ?> appears in a quoted string it'll screw up. But
meh, it's a 15 minute implementation.



A huge improvement would be to send the code to rdmd instead of a temp file then
dmd like I did here. rdmd will cache the executable and give it a unique temporary
name so it will be faster and less prone to overwrites. But that just now came to
my mind...



To use it like php, you'd just add an apache handler to treat those dhp files as a
CGI application... and you might need to add a shebang to the top too so the OS
knows what program to run.

A tiny apache module could probably get rid of the shebang requirement.




But this shows that it isn't terribly hard to make it work at least a little.


btw, loops work too:

===
Hello


<?d
        foreach(i; 0..5) {
?>
        Loops work too, like in PHP (<?= i ?>). Well, sort of; you don't have to
terminate it here which might be confusing. I saw add the braces anyway.

<?d } ?>
Bye!
=======

Prints out that inner text 5 times, as you'd expect... as long as you keep the
braces. Without the braces, it will only print the first part of the literal.
(Consider how the program works - take blocks of text and put out a write
statement for them. A foreach without braces would only call the first write; the
others are outside the loop.)


More information about the Digitalmars-d mailing list