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 }