1 module tardy.refraction;
2 
3 
4 /**
5    Returns a string mixin that is the function pointer type of F,
6    with an extra void* (or const(void)*) first parameter.
7  */
8 string vtableEntryRecipe(alias F)(in string symbolName = "")
9     in(__ctfe)
10     do
11 {
12     import std.conv: text;
13     import std.algorithm: canFind, among, filter;
14     import std.array: join;
15 
16     const symbol = symbolForTraits!F(symbolName);
17     enum attrs = [ __traits(getFunctionAttributes, F) ];
18 
19     enum isConst = attrs.canFind("const");
20     enum isImmutable = attrs.canFind("immutable");
21     enum isShared = attrs.canFind("shared");
22 
23     enum selfType = isConst
24         ? `const(void)*`
25         : isImmutable
26             ? `immutable(void)*`
27             : isShared
28                 ? `shared(void)*`
29                 : `void*`;
30 
31     static bool isMemberFunctionOnly(in string attr) {
32         return cast(bool) attr.among("const", "immutable", "shared", "inout", "return", "scope");
33     }
34 
35     const selfAttrs = attrs
36         .filter!(a => isMemberFunctionOnly(a) && !a.among("const", "immutable", "shared"))
37         .join(" ");
38     const vtableEntryAttrs = attrs
39         .filter!(a => !isMemberFunctionOnly(a))
40         .join(" ");
41 
42     return text(returnRecipe(symbol),
43                 ` function(`, selfAttrs, " ", selfType, `, `,
44                 parametersRecipe!F(symbol), `)`,
45                 vtableEntryAttrs);
46 }
47 
48 
49 /**
50    Returns a string to be mixed in that replicates the signature
51    of F. The string is meant to be mixed in inside a struct or class
52    so as to be a member function.
53  */
54 string methodRecipe(alias F)(in string symbolName = "")
55     in(__ctfe)
56      do
57 {
58     import std.conv: text;
59     import std.range: iota;
60     import std.algorithm: map;
61     import std.array: join;
62 
63     const symbol = symbolForTraits!F(symbolName);
64     enum name = __traits(identifier, F);
65     enum attrs = [ __traits(getFunctionAttributes, F) ].join(" ");
66 
67     return text(returnRecipe(symbol), `  `,
68                 name,
69                 `(`, parametersRecipe!F(symbol), `)`,
70                 ` `, attrs);
71 }
72 
73 
74 private string symbolForTraits(alias F)(in string symbolName = "")
75     in(__ctfe)
76     do
77 {
78     import std.traits: fullyQualifiedName;
79     return symbolName == "" ? fullyQualifiedName!F : symbolName;
80 }
81 
82 
83 private string returnRecipe(in string symbol)
84     @safe pure
85     in(__ctfe)
86     do
87 {
88     return `std.traits.ReturnType!(` ~ symbol ~ `)`;
89 }
90 
91 private string parametersRecipe(alias F)(in string symbol)
92     in(__ctfe)
93     do
94 {
95 
96     import std.array: join;
97     import std.traits: Parameters;
98 
99     string[] parameters;
100 
101     static foreach(i; 0 .. Parameters!F.length) {
102         parameters ~= parameterRecipe!(F, i)(symbol);
103     }
104 
105     return parameters.join(", ");
106 }
107 
108 
109 private string parameterRecipe(alias F, size_t i)(in string symbol)
110     in(__ctfe)
111     do
112 {
113     import std.array: join;
114     import std.conv: text;
115     import std.traits: ParameterDefaults;
116 
117     const string[] storageClasses = [ __traits(getParameterStorageClasses, F, i) ];
118 
119     static string defaultValue(alias default_)() {
120         static if(is(default_ == void))
121             return "";
122         else
123             return text(" = ", default_);
124     }
125 
126 
127     return
128         text(storageClasses.join(" "), " ",
129              `std.traits.Parameters!(`, symbol, `)[`, i, `] `,
130              `arg`, i,
131              defaultValue!(ParameterDefaults!F[i]),
132             );
133 }