1 /**
2  * Copyright: Copyright (c) 2017 Wojciech Szęszoł. All rights reserved.
3  * Authors: Wojciech Szęszoł
4  * Version: Initial created: October 13, 2017
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dstep.translator.TypeInference;
8 
9 import std.container.dlist;
10 import std.range;
11 import std.traits;
12 import std.variant;
13 
14 import clang.c.Index;
15 import clang.Cursor;
16 import clang.SourceLocation;
17 import clang.SourceRange;
18 import clang.Token;
19 import clang.TranslationUnit;
20 
21 import dstep.translator.Context;
22 import dstep.translator.MacroParser;
23 import dstep.translator.Preprocessor;
24 
25 struct Defined
26 {
27     string spelling;
28 }
29 
30 struct Generic
31 {
32 }
33 
34 struct Meta
35 {
36 }
37 
38 alias InferredType = Algebraic!(Defined, Generic, Meta);
39 
40 struct InferredSignature
41 {
42     InferredType result;
43     InferredType[] params;
44 
45     static InferredSignature fromDefinition(MacroDefinition definition)
46     {
47         import std.array;
48         import std.range;
49 
50         return InferredSignature(
51             InferredType(Generic.init),
52             repeat(InferredType(Generic.init), definition.params.length).array);
53     }
54 }
55 
56 void inferMacroSignature(
57     InferenceContext context,
58     TypedMacroDefinition currentDefinition)
59 {
60     inferMacroSignature(context, currentDefinition, currentDefinition.expr);
61 }
62 
63 void inferMacroSignature(
64     InferenceContext context,
65     TypedMacroDefinition currentDefinition,
66     Expression expression)
67 {
68     if (!expression.hasValue)
69         return;
70 
71     void pass(T)(T operator) { }
72 
73     bool isParamMeta(TypedMacroDefinition definition, string name)
74     {
75         import std.algorithm;
76         ptrdiff_t index = definition.params.countUntil(name);
77         return index != -1 && definition.signature.params[index].peek!Meta;
78     }
79 
80     return expression.visit!(
81         delegate void(CallExpr expression)
82         {
83             auto spelling = expression.spelling;
84 
85             if (spelling is null)
86                 return;
87 
88             auto definition = spelling in context.definitions;
89 
90             if (definition is null)
91                 return;
92 
93             auto updated = false;
94 
95             foreach (index, argument; expression.args)
96             {
97                 if (auto argumentIdentifier
98                     = argument.debraced.peek!Identifier)
99                 {
100                     if (isParamMeta(currentDefinition, argument.spelling) &&
101                         definition.signature.params[index].peek!Generic)
102                     {
103                         definition.signature.params[index] = Meta.init;
104                         updated = true;
105                     }
106                 }
107                 else if (auto argumentIdentifier
108                     = argument.debraced.peek!TypeIdentifier)
109                 {
110                     if (definition.signature.params[index].peek!Generic)
111                     {
112                         definition.signature.params[index] = Meta.init;
113                         updated = true;
114                     }
115                 }
116                 else
117                 {
118                     inferMacroSignature(context, currentDefinition, argument);
119                 }
120             }
121 
122             if (updated)
123                 context.queue.insertBack(*definition);
124         },
125         delegate void(SubExpr subExpr)
126         {
127             inferMacroSignature(context, currentDefinition, subExpr.subexpr);
128         },
129         pass);
130 }
131 
132 InferredType commonType(InferredType a, InferredType b)
133 {
134     if (a == b)
135         return a;
136     else
137         return InferredType(Generic.init);
138 }
139 
140 InferredType inferExpressionType(Expression expression)
141 {
142     import std.format : format;
143 
144     if (!expression.hasValue)
145         return InferredType.init;
146 
147     InferredType inferBinaryOperator(T)(T operator)
148     {
149         return commonType(
150             operator.left.inferExpressionType(),
151             operator.right.inferExpressionType());
152     }
153 
154     return expression.visit!(
155         delegate InferredType(Identifier identifier)
156         {
157             return InferredType(Generic.init);
158         },
159         delegate InferredType(TypeIdentifier identifier)
160         {
161             return InferredType(Meta.init);
162         },
163         delegate InferredType(Literal literal)
164         {
165             return InferredType(Defined("int"));
166         },
167         delegate InferredType(StringLiteral stringLiteral)
168         {
169             return InferredType(Defined("string"));
170         },
171         delegate InferredType(StringifyExpr stringifyExpr)
172         {
173             return InferredType(Defined("string"));
174         },
175         delegate InferredType(StringConcat stringConcat)
176         {
177             return InferredType(Defined("string"));
178         },
179         delegate InferredType(TokenConcat tokenConcat)
180         {
181             return InferredType(Defined("string"));
182         },
183         delegate InferredType(IndexExpr indexExpr)
184         {
185             return InferredType(Generic.init);
186         },
187         delegate InferredType(CallExpr callExpr)
188         {
189             return InferredType(Generic.init);
190         },
191         delegate InferredType(DotExpr dotExpr)
192         {
193             return InferredType(Generic.init);
194         },
195         delegate InferredType(ArrowExpr arrowExpr)
196         {
197             return InferredType(Generic.init);
198         },
199         delegate InferredType(SubExpr subExpr)
200         {
201             return subExpr.subexpr.inferExpressionType();
202         },
203         delegate InferredType(UnaryExpr unaryExpr)
204         {
205             if (unaryExpr.operator == "sizeof")
206                 return InferredType(Defined("size_t"));
207             else
208                 return unaryExpr.subexpr.inferExpressionType();
209         },
210         delegate InferredType(DefinedExpr literal)
211         {
212             return InferredType(Defined("int"));
213         },
214         delegate InferredType(SizeofType sizeofType)
215         {
216             return InferredType(Defined("size_t"));
217         },
218         delegate InferredType(CastExpr castExpr)
219         {
220             return InferredType(Generic.init);
221         },
222         inferBinaryOperator!MulExpr,
223         inferBinaryOperator!AddExpr,
224         inferBinaryOperator!SftExpr,
225         inferBinaryOperator!RelExpr,
226         inferBinaryOperator!EqlExpr,
227         inferBinaryOperator!AndExpr,
228         inferBinaryOperator!XorExpr,
229         inferBinaryOperator!OrExpr,
230         inferBinaryOperator!LogicalAndExpr,
231         inferBinaryOperator!LogicalOrExpr,
232         delegate InferredType(CondExpr condExpr)
233         {
234             return commonType(
235                 condExpr.left.inferExpressionType(),
236                 condExpr.right.inferExpressionType());
237         });
238 }
239 
240 class InferenceContext
241 {
242     Cursor[string] globalTypes;
243     DList!TypedMacroDefinition queue;
244     TypedMacroDefinition[string] definitions;
245 }
246 
247 class TypedMacroDefinition
248 {
249     MacroDefinition definition;
250     InferredSignature signature;
251     alias definition this;
252 
253     static TypedMacroDefinition fromDefinition(MacroDefinition definition)
254     {
255         auto result = new TypedMacroDefinition();
256         result.definition = definition;
257         result.signature = InferredSignature.fromDefinition(definition);
258         return result;
259     }
260 }
261 
262 TypedMacroDefinition[string] inferMacroSignatures(Context context)
263 {
264     import std.array;
265     import std.algorithm;
266     import std.range;
267 
268     auto macroDefinitions = parseMacroDefinitions(
269         context.translUnit.cursor.children(true),
270         context.typeNames());
271 
272     auto inferenceContext = new InferenceContext();
273     inferenceContext.globalTypes = context.typeNames();
274     inferenceContext.queue = DList!TypedMacroDefinition(
275         macroDefinitions.map!(TypedMacroDefinition.fromDefinition));
276     inferenceContext.definitions = assocArray(
277         zip(
278             inferenceContext.queue[]
279                 .map!((TypedMacroDefinition x) => x.definition.spelling),
280             inferenceContext.queue[]));
281 
282     while (!inferenceContext.queue.empty)
283     {
284         inferMacroSignature(
285             inferenceContext,
286             inferenceContext.queue.front);
287 
288         inferenceContext.queue.removeFront();
289     }
290 
291     foreach (definition; inferenceContext.definitions)
292         definition.signature.result = inferExpressionType(definition.expr);
293 
294     return inferenceContext.definitions;
295 }