digitalmars.D.learn - Mixin and function template?
- renoX (20/20) Feb 28 2007 Hello,
- Frits van Bommel (47/64) Feb 28 2007 This line is equivalent to:
- renoX (14/94) Feb 28 2007 In theory yes, in practice when I tried fwritef(fd, Fmt!(A)); it didn't...
- Frits van Bommel (73/108) Feb 28 2007 Oh, sorry. I should have seen that Fmt!() generates the arguments as a
- renoX (16/55) Mar 01 2007 The difference between your sputf and mine is that mine take a tuple
- Frits van Bommel (32/87) Mar 01 2007 For one thing, the ';' shouldn't be there. And the call syntax changes
- renoX (16/113) Mar 01 2007 Weird, the template that I had already for the 'writef equivalent' was:
- Frits van Bommel (34/82) Mar 01 2007 There are three kinds of mixins[1]: mixin declarations, mixin statements...
- Hasan Aljudy (71/93) Mar 01 2007 I wrote some code so that you could print local variables or expressions...
- renoX (9/119) Mar 01 2007 Thanks for your code, the syntax I used is inspired from Ruby #{} except...
Hello, I have a template which contain a single function: template sputf(A...) { char[] call() { auto fd=std.c.stdio.fopen("tmp_file", "w+"); mixin(`fwritef(fd,`~Fmt!(A)~`);`); std.c.stdio.fclose(fd); auto res = cast(char[])read("tmp_file"); return res; } } At the call site, I have to do the following: mixin sputf!("%d{x}") P1; res = P1.call(); which is quite ugly, so I'd like to convert the code in a 'function template' but when I do this, I don't manage to call the function without failure.. Does someone knows how to do it? Regards, renoX
Feb 28 2007
renoX wrote:I have a template which contain a single function:Let's start with that code...template sputf(A...) { char[] call() { auto fd=std.c.stdio.fopen("tmp_file", "w+");mixin(`fwritef(fd,`~Fmt!(A)~`);`);This line is equivalent to: fwritef(fd, Fmt!(A)); no mixin() required.std.c.stdio.fclose(fd); auto res = cast(char[])read("tmp_file");So basically, you're creating a temporary file, write some formatted output to it, then open it and put the contents in an allocated buffer? Why not just: auto res = std.string.format(Fmt!(A)); ? That should allocate a string and fill it with with the formatted data. AFAICT it's equivalent to the above code, except the code above creates a file to do it, and so can get into trouble if multiple versions of it get run at the same time from the same directory...return res;Also, you forgot to delete the file before returning. Unless that was intended? (I didn't think so :P)} }So: --- template sputf(A...) { char[] call() { return std.string.format(Fmt!(A)); } } --- should be pretty much identical to your code, except for tempfile-related issues in your version.At the call site, I have to do the following: mixin sputf!("%d{x}") P1; res = P1.call(); which is quite ugly, so I'd like to convert the code in a 'function template' but when I do this, I don't manage to call the function without failure.. Does someone knows how to do it?Well, presumably the function needs to access (local?) variable 'x'. That means you can't avoid using some kind of mixin if you want to do this. But I don't think the code left in the template is very ugly, so you could also just use it directly, like this: --- import std.string; // ... some stuff here ... // example function using Fmt!() char[] func(int x) { char[] res = format(Fmt!("%d{x}")); return res; } --- Which is probably cleaner than anything you'll get without: a) changing format() to be compile-time executable, or b) waiting until Walter sufficiently improves compile-time execution to allow current format() to be usable, or c) implementing a compile-time format-like function yourself (either as a compile-time executable function or through template meta programming).
Feb 28 2007
Frits van Bommel a écrit :renoX wrote:In theory yes, in practice when I tried fwritef(fd, Fmt!(A)); it didn't work..I have a template which contain a single function:Let's start with that code...template sputf(A...) { char[] call() { auto fd=std.c.stdio.fopen("tmp_file", "w+");mixin(`fwritef(fd,`~Fmt!(A)~`);`);This line is equivalent to: fwritef(fd, Fmt!(A)); no mixin() required.Because I didn't know this function, thanks for the suggestion. When I tried it didn't work though, unfortunately..std.c.stdio.fclose(fd); auto res = cast(char[])read("tmp_file");So basically, you're creating a temporary file, write some formatted output to it, then open it and put the contents in an allocated buffer? Why not just: auto res = std.string.format(Fmt!(A));That should allocate a string and fill it with with the formatted data. AFAICT it's equivalent to the above code, except the code above creates a file to do it, and so can get into trouble if multiple versions of it get run at the same time from the same directory...No, a small mistake.return res;Also, you forgot to delete the file before returning. Unless that was intended? (I didn't think so :P)It's not the mixin that I want to get rid of (I can't) but what I'd like is to rename the function call sputf and to have just one function call, this works for templates, but not for template function, weird..} }So: --- template sputf(A...) { char[] call() { return std.string.format(Fmt!(A)); } } --- should be pretty much identical to your code, except for tempfile-related issues in your version.At the call site, I have to do the following: mixin sputf!("%d{x}") P1; res = P1.call(); which is quite ugly, so I'd like to convert the code in a 'function template' but when I do this, I don't manage to call the function without failure.. Does someone knows how to do it?Well, presumably the function needs to access (local?) variable 'x'. That means you can't avoid using some kind of mixin if you want to do this.But I don't think the code left in the template is very ugly, so you could also just use it directly, like this: --- import std.string; // ... some stuff here ... // example function using Fmt!() char[] func(int x) { char[] res = format(Fmt!("%d{x}")); return res; } --- Which is probably cleaner than anything you'll get without: a) changing format() to be compile-time executable, or b) waiting until Walter sufficiently improves compile-time execution to allow current format() to be usable, or c) implementing a compile-time format-like function yourself (either as a compile-time executable function or through template meta programming).Fmt! is doing c), it is limitated of course because I choose not to parse a string and templates do not accept expressions.. The fact that format is not working, nor fwrite(fd but mixin(fwrite(fd works make me thing of a bug.. renoX
Feb 28 2007
renoX wrote:Frits van Bommel a écrit :Oh, sorry. I should have seen that Fmt!() generates the arguments as a string, not a tuple. So you'd still need the mixin wrapper here.renoX wrote:> no mixin() required. In theory yes, in practice when I tried fwritef(fd, Fmt!(A)); it didn't work..mixin(`fwritef(fd,`~Fmt!(A)~`);`);This line is equivalent to: fwritef(fd, Fmt!(A));This should be equivalent to your original[1]: auto res = mixin("std.string.format(" ~ Fmt!(A) ~ ")"); [1]: Of course, my previous suggestion *should* have been equivalent as well. Unfortunately it wasn't ;).Because I didn't know this function, thanks for the suggestion. When I tried it didn't work though, unfortunately..std.c.stdio.fclose(fd); auto res = cast(char[])read("tmp_file");So basically, you're creating a temporary file, write some formatted output to it, then open it and put the contents in an allocated buffer? Why not just: auto res = std.string.format(Fmt!(A));You could have a compile-time function generate a string that calls the appropriate code. Here's what I came up with: --- import std.stdio; import std.string; /** dummy Fmt!() for testing. This example assumes it accepts a * single string and returns format() parameters in string form. */ template Fmt(char[] A) { const char[] Fmt = `"%d", x`; } /** Ensures escape codes and quotes in strings are escaped themselves. * Not thoroughly checked, but the idea is that the following should * hold for all strings: * --- * string == mixin(escape(string)); * --- */ char[] escape(char[] string) { char[] result = "\""; foreach (c; string) { if (c == '\\') result ~= "\\\\"; else if (c == '"') result ~= "\\\""; else result ~= c; } result ~= "\""; return result; } /** The input must be a format string with embedded "%d{var}"-style * formatting commands */ char[] sputf(char[] string) { return "mixin(`std.string.format(` ~ Fmt!(" ~ escape(string) ~ ") ~ `)`)"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf("%d{x}")); writefln("%s", ret); } --- As short as it is, it took me a while to get it that way. This is playing with meta-levels. It mixes in a string containing a mixin expression. It used to be even worse though: At first the sputf() function was just a wrapper around an adapted sputf!() template, but all the call() function did was return a mixed-in expression, which was then wrapped into a string that - when mixed in - assigned the second-level mixed-in result to a variable passed by name. So it mixed in a string, that mixed in a template, that mixed in an expression -- a three-level mixin. (Careful: multiple meta-levels like that can get really confusing really quick :P) Then I figured, that template mixin (sputfImpl!(), specifically the call() member) must be inlinable ;). After adding an escape() function around the format string, the result is what you see above: short but sweet. I hope you agree that --- ret = mixin(sputf("%d{x}")); --- is a pretty good syntax :).It's not the mixin that I want to get rid of (I can't) but what I'd like is to rename the function call sputf and to have just one function call, this works for templates, but not for template function, weird..At the call site, I have to do the following: mixin sputf!("%d{x}") P1; res = P1.call(); which is quite ugly, so I'd like to convert the code in a 'function template' but when I do this, I don't manage to call the function without failure.. Does someone knows how to do it?Well, presumably the function needs to access (local?) variable 'x'. That means you can't avoid using some kind of mixin if you want to do this.
Feb 28 2007
Frits van Bommel a écrit : [cut]/** The input must be a format string with embedded "%d{var}"-style * formatting commands */ char[] sputf(char[] string) { return "mixin(`std.string.format(` ~ Fmt!(" ~ escape(string) ~ ") ~ `)`)"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf("%d{x}")); writefln("%s", ret); }The difference between your sputf and mine is that mine take a tuple sputf(A...) instead of a string, is it be possible to have a function template take a tuple as an argument that is to say to have something like char[] sputf(A...)() { return "std.string.format("~Fmt!(A) ~ ");"; } And still call it like you do above? It doesn't work when I try to do this, I don't understand why..--- As short as it is, it took me a while to get it that way. This is playing with meta-levels. It mixes in a string containing a mixin expression. It used to be even worse though: At first the sputf() function was just a wrapper around an adapted sputf!() template, but all the call() function did was return a mixed-in expression, which was then wrapped into a string that - when mixed in - assigned the second-level mixed-in result to a variable passed by name. So it mixed in a string, that mixed in a template, that mixed in an expression -- a three-level mixin. (Careful: multiple meta-levels like that can get really confusing really quick :P)Yes, I find it very easy to be confused.Then I figured, that template mixin (sputfImpl!(), specifically the call() member) must be inlinable ;). After adding an escape() function around the format string, the result is what you see above: short but sweet. I hope you agree that --- ret = mixin(sputf("%d{x}")); --- is a pretty good syntax :).I agree, but it's a limited one: you cannot do mixin(sputf("%d",x)) I wanted to syntax to be compatible with the old printf syntax.. Regards, renoX
Mar 01 2007
renoX wrote:Frits van Bommel a écrit : [cut]For one thing, the ';' shouldn't be there. And the call syntax changes slightly, you need to add the '!' to indicate they're template parameters instead of function parameters. (the function call parentheses can be left off due to property syntax) Then you get this: --- import std.stdio; import std.string; /** dummy Fmt!() for testing. This example assumes it accepts a * tuple and returns format() parameters in string form. */ template Fmt(A...) { const char[] Fmt = `"%d", x`; } char[] sputf(A...)() { return "std.string.format(" ~ Fmt!(A) ~ ")"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf!("%d{x}")); writefln("%s", ret); } --- which seems to work./** The input must be a format string with embedded "%d{var}"-style * formatting commands */ char[] sputf(char[] string) { return "mixin(`std.string.format(` ~ Fmt!(" ~ escape(string) ~ ") ~ `)`)"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf("%d{x}")); writefln("%s", ret); }The difference between your sputf and mine is that mine take a tuple sputf(A...) instead of a string, is it be possible to have a function template take a tuple as an argument that is to say to have something like char[] sputf(A...)() { return "std.string.format("~Fmt!(A) ~ ");"; } And still call it like you do above? It doesn't work when I try to do this, I don't understand why..The above is actually much clearer in implementation. A bit less nice in call syntax, but not by much.As short as it is, it took me a while to get it that way. This is playing with meta-levels. It mixes in a string containing a mixin expression. It used to be even worse though: At first the sputf() function was just a wrapper around an adapted sputf!() template, but all the call() function did was return a mixed-in expression, which was then wrapped into a string that - when mixed in - assigned the second-level mixed-in result to a variable passed by name. So it mixed in a string, that mixed in a template, that mixed in an expression -- a three-level mixin. (Careful: multiple meta-levels like that can get really confusing really quick :P)Yes, I find it very easy to be confused.Is the above what you were looking for?Then I figured, that template mixin (sputfImpl!(), specifically the call() member) must be inlinable ;). After adding an escape() function around the format string, the result is what you see above: short but sweet. I hope you agree that --- ret = mixin(sputf("%d{x}")); --- is a pretty good syntax :).I agree, but it's a limited one: you cannot do mixin(sputf("%d",x)) I wanted to syntax to be compatible with the old printf syntax..
Mar 01 2007
Frits van Bommel a écrit :renoX wrote:Weird, the template that I had already for the 'writef equivalent' was: template putf(A...) { const char[] putf = "writef(" ~ Fmt!(A) ~ ");"; } Here the ';' didn't create a problem, it's string that in the sputf template function it creates a problem..Frits van Bommel a écrit : [cut]For one thing, the ';' shouldn't be there./** The input must be a format string with embedded "%d{var}"-style * formatting commands */ char[] sputf(char[] string) { return "mixin(`std.string.format(` ~ Fmt!(" ~ escape(string) ~ ") ~ `)`)"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf("%d{x}")); writefln("%s", ret); }The difference between your sputf and mine is that mine take a tuple sputf(A...) instead of a string, is it be possible to have a function template take a tuple as an argument that is to say to have something like char[] sputf(A...)() { return "std.string.format("~Fmt!(A) ~ ");"; } And still call it like you do above? It doesn't work when I try to do this, I don't understand why..And the call syntax changes slightly, you need to add the '!' to indicate they're template parameters instead of function parameters.Yes.(the function call parentheses can be left off due to property syntax)I hadn't realised that the removal of the parenthesis was due to the property syntax..Then you get this: --- import std.stdio; import std.string; /** dummy Fmt!() for testing. This example assumes it accepts a * tuple and returns format() parameters in string form. */ template Fmt(A...) { const char[] Fmt = `"%d", x`; } char[] sputf(A...)() { return "std.string.format(" ~ Fmt!(A) ~ ")"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf!("%d{x}")); writefln("%s", ret); } --- which seems to work.Yes, but what is a bit strange is that if x is an int variable res = mixin(sputf!("%d",x)); fails (it works if x is a const int) but mixin(putf!("%d",x)); works (putf being the template given above).Yes, thanks a lot. renoXThe above is actually much clearer in implementation. A bit less nice in call syntax, but not by much.As short as it is, it took me a while to get it that way. This is playing with meta-levels. It mixes in a string containing a mixin expression. It used to be even worse though: At first the sputf() function was just a wrapper around an adapted sputf!() template, but all the call() function did was return a mixed-in expression, which was then wrapped into a string that - when mixed in - assigned the second-level mixed-in result to a variable passed by name. So it mixed in a string, that mixed in a template, that mixed in an expression -- a three-level mixin. (Careful: multiple meta-levels like that can get really confusing really quick :P)Yes, I find it very easy to be confused.Is the above what you were looking for?Then I figured, that template mixin (sputfImpl!(), specifically the call() member) must be inlinable ;). After adding an escape() function around the format string, the result is what you see above: short but sweet. I hope you agree that --- ret = mixin(sputf("%d{x}")); --- is a pretty good syntax :).I agree, but it's a limited one: you cannot do mixin(sputf("%d",x)) I wanted to syntax to be compatible with the old printf syntax..
Mar 01 2007
renoX wrote:Frits van Bommel a écrit :There are three kinds of mixins[1]: mixin declarations, mixin statements and mixin expressions. Your putf string is used as a mixin statement, while the sputf string is used as a mixin expression. See http://www.digitalmars.com/d/changelog.html#new1_005 for the spec links, but essentially mixin statements generate statements (including any terminating ';'s) while mixin expressions just generate (sub)expressions, which don't contain ';'s. [1] excluding template mixins, which are a different beast altogether.renoX wrote:Weird, the template that I had already for the 'writef equivalent' was: template putf(A...) { const char[] putf = "writef(" ~ Fmt!(A) ~ ");"; } Here the ';' didn't create a problem, it's string that in the sputf template function it creates a problem..char[] sputf(A...)() { return "std.string.format("~Fmt!(A) ~ ");"; } And still call it like you do above? It doesn't work when I try to do this, I don't understand why..For one thing, the ';' shouldn't be there.The behaviors differ? That's a bit weird... They both use template parameters, so they should have the exact same restrictions AFAIK. [a bit of research later] I think this is a restriction of compile-time function evaluation. From http://www.digitalmars.com/d/function.html#interpretation : --- expressions in the function may not: [snip] * reference any global state or variables * reference any local static variables [snip] --- Those /could/ be interpreted to disallow alias template parameter usage... Luckily the fix is easy, just transform it to be similar to your putf template to avoid CTFE: --- template sputf(A...) { const sputf = "std.string.format(" ~ Fmt!(A) ~ ")"; } --- works perfectly fine, even with non-constant integer variables as parameters. And the call syntax didn't even change :).Then you get this: --- import std.stdio; import std.string; /** dummy Fmt!() for testing. This example assumes it accepts a * tuple and returns format() parameters in string form. */ template Fmt(A...) { const char[] Fmt = `"%d", x`; } char[] sputf(A...)() { return "std.string.format(" ~ Fmt!(A) ~ ")"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf!("%d{x}")); writefln("%s", ret); } --- which seems to work.Yes, but what is a bit strange is that if x is an int variable res = mixin(sputf!("%d",x)); fails (it works if x is a const int) but mixin(putf!("%d",x)); works (putf being the template given above).
Mar 01 2007
Frits van Bommel a écrit :renoX wrote:Great! Thanks a lot! renoXFrits van Bommel a écrit :There are three kinds of mixins[1]: mixin declarations, mixin statements and mixin expressions. Your putf string is used as a mixin statement, while the sputf string is used as a mixin expression. See http://www.digitalmars.com/d/changelog.html#new1_005 for the spec links, but essentially mixin statements generate statements (including any terminating ';'s) while mixin expressions just generate (sub)expressions, which don't contain ';'s. [1] excluding template mixins, which are a different beast altogether.renoX wrote:Weird, the template that I had already for the 'writef equivalent' was: template putf(A...) { const char[] putf = "writef(" ~ Fmt!(A) ~ ");"; } Here the ';' didn't create a problem, it's string that in the sputf template function it creates a problem..char[] sputf(A...)() { return "std.string.format("~Fmt!(A) ~ ");"; } And still call it like you do above? It doesn't work when I try to do this, I don't understand why..For one thing, the ';' shouldn't be there.The behaviors differ? That's a bit weird... They both use template parameters, so they should have the exact same restrictions AFAIK. [a bit of research later] I think this is a restriction of compile-time function evaluation. From http://www.digitalmars.com/d/function.html#interpretation : --- expressions in the function may not: [snip] * reference any global state or variables * reference any local static variables [snip] --- Those /could/ be interpreted to disallow alias template parameter usage... Luckily the fix is easy, just transform it to be similar to your putf template to avoid CTFE: --- template sputf(A...) { const sputf = "std.string.format(" ~ Fmt!(A) ~ ")"; } --- works perfectly fine, even with non-constant integer variables as parameters. And the call syntax didn't even change :).Then you get this: --- import std.stdio; import std.string; /** dummy Fmt!() for testing. This example assumes it accepts a * tuple and returns format() parameters in string form. */ template Fmt(A...) { const char[] Fmt = `"%d", x`; } char[] sputf(A...)() { return "std.string.format(" ~ Fmt!(A) ~ ")"; } void main(char[][] args) { char[] ret; int x = 2007; ret = mixin(sputf!("%d{x}")); writefln("%s", ret); } --- which seems to work.Yes, but what is a bit strange is that if x is an int variable res = mixin(sputf!("%d",x)); fails (it works if x is a const int) but mixin(putf!("%d",x)); works (putf being the template given above).
Mar 02 2007
Here's the result. Fixing my problems with sputf! helped me shorten the self-test part in the main function. So thanks again. renoX
Mar 02 2007
renoX wrote:Hello, I have a template which contain a single function: template sputf(A...) { char[] call() { auto fd=std.c.stdio.fopen("tmp_file", "w+"); mixin(`fwritef(fd,`~Fmt!(A)~`);`); std.c.stdio.fclose(fd); auto res = cast(char[])read("tmp_file"); return res; } } At the call site, I have to do the following: mixin sputf!("%d{x}") P1; res = P1.call(); which is quite ugly, so I'd like to convert the code in a 'function template' but when I do this, I don't manage to call the function without failure.. Does someone knows how to do it? Regards, renoXI wrote some code so that you could print local variables or expressions by wrapping them with {{ double braces }} inside the string (this is a Django idiom). The code is not so stable as it doesn't do anything about escaping and stuff .. and it's not really tested at all .. except for one use-case; it's the intended typical usage: auto name = "hasan"; mixin( bang( "hello {{name}}, how are you?" ) ); the idea is to replace bang("string1 {{expr}} string2") with writefln( "string1", expr, "string2" ); Here's the code, it's written in an ugly aggressive way because it was my first attempt to play with mixins & compile-time functions, so I stayed as low-level as possible. ------------ import std.stdio; char[] parse( char[] string ) { char[] result = ""; int index = 0; while( index < string.length ) { //scan for {{ bool sequence = false; int start = index; while(index < string.length) { if( (index < string.length-2) ) { if( (string[index] == '{') && (string[index+1] == '{') ) { sequence = true; break; } } index++; } auto raw = string[start..index]; //this holds the contents of string up to the first "{{" if there is one. if( result.length > 0 ) result = result ~ ", "; result = result ~ `"` ~ raw ~ `"`; if( sequence ) { index+= 2; start = index; //look for }} while( (index < string.length-2) ) { if( (string[index] == '}') && (string[index+1] == '}') ) break; index++; } auto exp = string[start..index]; result = result ~ ", " ~ exp; index += 2; } } return result; } char[] bang( char[] expr ) { expr = parse(expr); return `writefln(` ~ expr ~ `);`; } void main() { auto name = "hasan"; mixin( bang( "hello {{name}}, how are you?" ) ); } ----------
Mar 01 2007
Hasan Aljudy a écrit :renoX wrote:that I thought that in printf '%' is the escape char, that's why I'm using %s{} or %d{} (and %{ as equivalent to '{') We're doing more or less the same thing, except that my implementation takes a tuple instead of just one string which allows to be a little bit compatible with printf: mixin(putf!("%d",x)) works. But I have a hard time making the equivalent of for format/sprintf.. renoXHello, I have a template which contain a single function: template sputf(A...) { char[] call() { auto fd=std.c.stdio.fopen("tmp_file", "w+"); mixin(`fwritef(fd,`~Fmt!(A)~`);`); std.c.stdio.fclose(fd); auto res = cast(char[])read("tmp_file"); return res; } } At the call site, I have to do the following: mixin sputf!("%d{x}") P1; res = P1.call(); which is quite ugly, so I'd like to convert the code in a 'function template' but when I do this, I don't manage to call the function without failure.. Does someone knows how to do it? Regards, renoXI wrote some code so that you could print local variables or expressions by wrapping them with {{ double braces }} inside the string (this is a Django idiom).The code is not so stable as it doesn't do anything about escaping and stuff .. and it's not really tested at all .. except for one use-case; it's the intended typical usage: auto name = "hasan"; mixin( bang( "hello {{name}}, how are you?" ) ); the idea is to replace bang("string1 {{expr}} string2") with writefln( "string1", expr, "string2" ); Here's the code, it's written in an ugly aggressive way because it was my first attempt to play with mixins & compile-time functions, so I stayed as low-level as possible. ------------ import std.stdio; char[] parse( char[] string ) { char[] result = ""; int index = 0; while( index < string.length ) { //scan for {{ bool sequence = false; int start = index; while(index < string.length) { if( (index < string.length-2) ) { if( (string[index] == '{') && (string[index+1] == '{') ) { sequence = true; break; } } index++; } auto raw = string[start..index]; //this holds the contents of string up to the first "{{" if there is one. if( result.length > 0 ) result = result ~ ", "; result = result ~ `"` ~ raw ~ `"`; if( sequence ) { index+= 2; start = index; //look for }} while( (index < string.length-2) ) { if( (string[index] == '}') && (string[index+1] == '}') ) break; index++; } auto exp = string[start..index]; result = result ~ ", " ~ exp; index += 2; } } return result; } char[] bang( char[] expr ) { expr = parse(expr); return `writefln(` ~ expr ~ `);`; } void main() { auto name = "hasan"; mixin( bang( "hello {{name}}, how are you?" ) ); } ----------
Mar 01 2007