OT: Re: DConf Hackathon Ideas

via Digitalmars-d digitalmars-d at puremagic.com
Fri Apr 28 06:31:33 PDT 2017


On Friday, 28 April 2017 at 10:09:32 UTC, Moritz Maxeiner wrote:
> On Friday, 28 April 2017 at 09:52:29 UTC, Petar Kirov 
> [ZombineDev] wrote:
>>
>> AST introspection - given a function definition (!= 
>> declaration, i.e. the body is available) f, the expression 
>> __traits(ast, f) should return an instance of FuncDeclaration 
>> (https://github.com/dlang/dmd/blob/197ff0fd84b7b101f47458ab06e5b6f95959941e/src/ddmd/astnull.d#L151) with all of its members filled. The class-es used to represent the AST should be plain old data types (i.e. should contain no functionality). The AST as produced by the parser should be returned, without any semantic analysis (which can modify it). No backwards compatibility guarantees should be made about __traits(ast, f) at least for a couple of years.
>>
>
> This sounds interesting, but could you expand on what this 
> enables/improves compared to CTFE+mixins?

CTFE and mixins are building blocks, needed to for my idea to 
actually useful.
Currently if you want to introspect a piece of code (function 
body) at compile time,
you need to duplicate the code in a string and then pass this 
string to a
CTFE-able D parser. As you can imagine, even with Stefan's new 
CTFE engine,
this would be orders of magnitude slower than just reusing the 
work that parser
inside the compiler *has already done* anyway. This makes such 
code introspection
infeasible for large projects. Strings (at least until mixined)
can contain uncompilable source (though lexically valid, in the 
case of q{}),
further complicating the matter. Additionally, the fact that you 
need to
keep the source code and the strings in sync is just stupid, 
violating DRY
at a whole new level.

In addition to AST introspection, AST transformation should be as 
easy as:

mixin template profileFunctionStatements(alias func, string 
newFunctionName)
{
     enum funcAst = __traits(ast, func);
     enum newAst = insertProfiling(funcAst, newFunctionName);
     mixin(newAst.toString());

     // a further optimization would be AST mixins, which
     // could directly be used by the compiler, instead of
     // first converting the AST to string and then
     // parsing it after mixing:
     mixin(newAst);
}

void main()
{
     int local = 42;

     void fun(int[] arr)
     {
         import std.conv : text;
         import std.file : remove, write;
         arr[] += local;
         string s = text(arr);
         "delete-me.txt".write(s);
     }

     mixin profileFunctionStatements!(print, `funInstrumented`);

     import std.array : array;
     import std.range : iota;
     funInstrumented(10000.iota.array);
}

Output:
{  arr[] += local;  } took 0.002 miliseconds to execute.
{  string s = text(arr);  } took 1.8052 miliseconds to execute.
{ "delete-me.txt".write(s); } took 7.746 miliseconds to execute.

Where funInstrumented could be generated to something like this:

void funInstrumented(int[] arr)
{
     import std.datetime : __Sw = StopWatch, __to = to; // 
generated
     import std.stdio : __wfln = writefln; // generated
     import std.conv : text;
     import std.file : remove, write;

     __Sw __sw; // generated

     __sw.start(); // generated
     arr[] += local;
     __sw.stop(); // generated
     __wfln("{ %s } took %s miliseconds to execute.",
         q{ arr[] += local; },
         __sw.peek().__to!("msecs", double)); // generated

     __sw.start(); // generated
     string s = text(arr);
     __sw.stop(); // generated
     __wfln("{ %s } took %s miliseconds to execute.",
         q{ string s = text(arr); },
         __sw.peek().__to!("msecs", double)); // generated

     __sw.start(); // generated
     "delete-me.txt".write(s);
      __sw.stop(); // generated
     __wfln("{%s} took %s miliseconds to execute.",
         q{ "delete-me.txt".write(s); },
         __sw.peek().__to!("msecs", double)); // generated
}

Other applications include:
* compiling/transpiling D functions to targets
like JS, SPIR-V, WebAssembly, etc. using CTFE.
* CTFE-driven code diagnostics (linting)
* Adding semantic to user defined attributes:
   E.g. @asyncSafe attribute for use in libraries like vibe.d that 
allows calling only
   functions marked as @asyncSafe from @asyncSafe code. That way 
libraries can
   introduce *and enforce* correct use of UDAs without any need 
for language changes.
* ...


More information about the Digitalmars-d mailing list