1 /**
2    Tests for using CTFE mirror to wrap calling D code from a foreign language.
3  */
4 module ut.ctfe.reflection.wrap;
5 
6 
7 import ut.ctfe.reflection;
8 
9 
10 @("blub.add1")
11 unittest {
12     import blub;
13     import std.format: format;
14 
15     enum mod = module_!"modules.functions";
16     enum add1 = mod.functionsByOverload[0];
17 
18     enum mixinStr = blubWrapperMixin(add1);
19     //pragma(msg, mixinStr);
20     mixin(mixinStr);
21 
22     wrap(Blub(1), Blub(2)).should == Blub(4);
23 }
24 
25 
26 @("blub.concatFoo")
27 unittest {
28     import blub;
29     import std.format: format;
30 
31     enum mod = module_!"modules.functions";
32     enum concatFoo = mod.functionsByOverload[10];
33 
34     enum mixinStr = blubWrapperMixin(concatFoo);
35     //pragma(msg, mixinStr);
36     mixin(mixinStr);
37 
38     wrap(Blub("hmmm"), Blub(42), Blub("quux")).should == Blub("hmmm42quuxfoo");
39 }
40 
41 
42 // Returns a string to be mixed in that defines a function `wrap`
43 // That calls converts blub types to D ones, calls `function_` then
44 // converts the result from D to blub.
45 private string blubWrapperMixin(Function function_) @safe pure {
46     assert(__ctfe);
47 
48     import std.array: join;
49     import std.algorithm: map;
50     import std.range: iota;
51     import std.format: format;
52 
53     string[] lines;
54 
55     static string argName(size_t i) {
56         import std.conv: text;
57         return text("arg", i);
58     }
59 
60     const numParams = function_.parameters.length;
61     // what goes in the function signature between the parens
62     const wrapParams = numParams
63         .iota
64         .map!(i => "Blub " ~ argName(i))
65         .join(", ")
66         ;
67     // the arguments to pass to the wrapped D function
68     const dArgs = numParams
69         .iota
70         .map!(i => argName(i) ~ ".to!(" ~ function_.parameters[i].type.name ~ ")")
71         .join(", ")
72         ;
73 
74     return q{
75         auto wrap(%s /*dArgs*/)
76         {
77             import blub: toBlub, to;
78             %s  // import mixin
79             return %s.toBlub;
80         }
81     }.format(
82         wrapParams,
83         function_.importMixin,
84         function_.callMixin(dArgs)
85     );
86 }