PHP-style (embedded variables) print statements

Ary Manzana ary at esperanto.org.ar
Thu May 31 08:48:05 PDT 2007


Can this be used for non-constant values?

Don Clugston escribió:
> With CTFE and text mixins, it is now reasonably straightforward to 
> implement PHP-style 'dollar' embedded variables, in a type-safe manner.
> 
> For example, the attached code (rough draft) allows you to write things 
> like:
> 
> int i;
> const k = 8;
> char [] str;
> mixin(dprint("current=$i next=$(i+1) const=$(k*3) $str\n"));
> 
> which is typesafe, converts all compile-time constants directly into the 
> format string, and converts everything else into a simple printf() call. 
> The mixin line above becomes
> 
> printf("current=%d next=%d const=24 %.*s\n", i, i+1, str);
> 
> Note that unlike a tuple solution, it does not cause any template bloat.
> Also doesn't have some of writefln's pitfalls (the case where a string 
> contains a % character).
> 
> Incidentally, this could do a lot better than printf, because it could 
> categorise the expressions. Eg, if there are no floating point 
> variables, it could translate it to a simple print function which 
> doesn't have the FP conversion code. Ditto for outputting arrays and 
> objects. Other optimisations are possible - eg, it could also estimate 
> how much buffer space is going to be required.
> 
> Downsides:
> (1) need to use "mixin()" until we get macros.
> (2) doesn't look like anything that's in D right now.
> (3) how are IDE's going to know when a string contains embedded variables?
> 
> Opinions? Is something like this worth considering as an alternative to 
> writefln, and to Tango's C# formatting and whisper syntax?
> 
> 
> ------------------------------------------------------------------------
> 
> module DPrint;
> 
> /// Convert an integer of type T to string.
> /// Note: this function is CTFE-compatible, but not very efficient at runtime
> char [] ct_itoa(T)(T x)
> {
>     char [] s="";
>     static if (is(T==byte)||is(T==short)||is(T==int)||is(T==long)) {
>         if (x<0) {
>             s = "-";
>             x = -x;
>         }
>     }
>     do {
>         s = cast(char)('0' + (x%10)) ~ s;
>         x/=10;
>     } while (x>0);
>     return s;
> }
> 
> // Templates to return string representation of floating-point constant.
> // This works, but only for floating-point constants -- should really create a
> // CTFE-compatible ftoa().
> char [] mixin_ftoa(real x)() {
>     return `"` ~ x.stringof ~ `"`;
> }
> 
> char [] mixin_ftoa(ireal x)() {
>     return `"` ~ x.stringof ~ `"`;
> }
> char [] mixin_ftoa(creal x)() {
>     return `"` ~ x.stringof ~ `"`;
> }
> 
> /** Evaluate a textual expression of type T, and return it as a textual literal.
>  *
>  */
> char [] dollar_convert(T)(char [] x)
> {
>     static if (is(T ==long))
>         return `"%Ld"`;
>     else static if (is(T==ulong)) return `"%Lu"`;
>     else static if (is(T:int)) return `"%d"`;
>     else static if (is(T:uint)) return `"%u"`;
>     else static if (is(T==real)) return `"%Lg"`;
>     else static if (is(T:double)) return `"%g"`;
>     else static if (is(T==char[])) return `"%.*s"`;
>     else return x;
> }
> 
> private {
> // BUGS: Many other UTF chars should be allowed inside identifiers.
> bool isIdentifierChar(char c)
> {
>     return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || (c=='_');
> }
> }
> 
> /**  Evaluate a string containing embedded 'dollar expressions'.
>  *
>  * Given a string containing embedded expression marked with 'dollar' indicators,
>  * returns a string which, when mixed in, will evaluate to a new string with all
>  * of the expressions evaluated.
>  * The expressions can be strings, or any integral type, or a floating-point
>  * constant (real, imaginary or complex) expression.
>  * Dollar expressions consist of a dollar sign, followed by a variable name
>  * (the first non-identifier character marks the end), or a dollar sign followed
>  * by an expression in parentheses. Two consecutive dollar signs become a dollar
>  * character.
>  */
> char [] dprint(char [] s)
> {
>     char [] result=`printf(("`;
>     char [] vars="";
>     int i=0;
>     while (i<s.length) {
>         if (i<s.length-1 && s[i]=='$') {
>             if (s[i+1]=='$') {
>                 result~='$'; // replace "$$" with '$'.
>                 i+=2;
>             } else { // replace "$expression" with the expression
>                 int start=i+1;
>                 int parenCount=0;
>                 if (s[start]=='(') {
>                     ++start;
>                     parenCount++;
>                 }
>                 for (i=start; i<s.length; ++i) {
>                     if (s[i]=='(') ++parenCount;
>                     if (s[i]==')') { --parenCount; if (parenCount==0) break; }
>                     if (parenCount==0 && !isIdentifierChar(s[i]))  break;
>                 }
>                 // Evaluate the expression, and convert it to a string
>                 vars ~="," ~ s[start..i];
>                 result ~= `"~mixin(dollar_convert!(typeof(`
>                        ~ s[start..i] ~ `))("` ~ s[start..i] ~ `"))~"`;
> 
> 
>                 if (s[i]==')') ++i;
>             }
>         }
>         else {
>             if (s[i]=='"') result ~= `\"`; // Retain embedded quotes.
>             else result ~= s[i];
>             ++i;
>         }
>      }
>      return result~ `").ptr`~vars ~ `);`;
> }
> 
> //-----------------
> // Example
> 
> void main()
> {
>     int k=56;
>     const int k2=7;
>     const double q = 4.1432e58;
>     const q2 = 4.1432e58;
> char [] x ="this is a string";
> const x2 ="this is a const string";
>     mixin(dprint(`The value of q2 is: $(q2*7) and k dollars is $$$k, but k2 is $k2 followed by $(k2 *5+1) and the floating point expression is $(q*2.18), string x is: $x and $x2 `));
> }



More information about the Digitalmars-d mailing list