1 /** 2 Function translations. 3 */ 4 module dpp.cursor.function_; 5 6 import dpp.from; 7 8 string[] translateFunction(in from!"clang".Cursor cursor, 9 ref from!"dpp.runtime.context".Context context) 10 @safe 11 { 12 import dpp.cursor.dlang: maybeRename, maybePragma; 13 import dpp.cursor.aggregate: maybeRememberStructs; 14 import dpp.type: translate; 15 import clang: Cursor, Type, Language; 16 import std.array: join, array; 17 import std.conv: text; 18 import std.algorithm: any, endsWith; 19 import std.typecons: Yes; 20 21 assert( 22 cursor.kind == Cursor.Kind.FunctionDecl || 23 cursor.kind == Cursor.Kind.CXXMethod || 24 cursor.kind == Cursor.Kind.Constructor || 25 cursor.kind == Cursor.Kind.Destructor 26 ); 27 28 // FIXME: Ignore move constructors for now 29 if(cursor.kind == Cursor.Kind.Constructor) { 30 auto paramTypes = paramTypes(cursor); 31 if(paramTypes.any!(a => a.kind == Type.Kind.RValueReference)) 32 return []; 33 } 34 35 const indentation = context.indentation; 36 context.log("Function return type (raw): ", cursor.type.returnType); 37 38 const returnType = cursor.kind == Cursor.Kind.Constructor || cursor.kind == Cursor.Kind.Destructor 39 ? "" 40 : translate(cursor.returnType, context, Yes.translatingFunction); 41 42 context.setIndentation(indentation); 43 context.log("Function return type (translated): ", returnType); 44 45 maybeRememberStructs(paramTypes(cursor), context); 46 47 // Here we used to check that if there were no parameters and the language is C, 48 // then the correct translation in D would be (...); 49 // However, that's not allowed in D. It just so happens that C production code 50 // exists that doesn't bother with (void), so instead of producing something that 51 // doesn't compile, we compromise and assume the user meant (void) 52 53 const paramTypes = translateParamTypes(cursor, context).array; 54 const isVariadic = cursor.type.spelling.endsWith("...)"); 55 const variadicParams = isVariadic ? "..." : ""; 56 const allParams = paramTypes ~ variadicParams; 57 58 const spelling = () { 59 if(cursor.kind == Cursor.Kind.Constructor) return "this"; 60 if(cursor.kind == Cursor.Kind.Destructor) return "~this"; 61 return context.rememberLinkable(cursor); 62 }(); 63 64 // const C++ method? 65 const const_ = cursor.type.spelling.endsWith(") const") ? " const" : ""; 66 67 return [ 68 maybePragma(cursor, context) ~ 69 text(returnType, " ", spelling, "(", allParams.join(", "), ") @nogc nothrow", const_, ";") 70 ]; 71 } 72 73 auto translateParamTypes(in from!"clang".Cursor cursor, 74 ref from!"dpp.runtime.context".Context context) 75 @safe 76 { 77 import dpp.type: translate; 78 import std.algorithm: map; 79 import std.range: tee; 80 import std.typecons: Yes; 81 82 return paramTypes(cursor) 83 .tee!((a){ context.log("Function Child: ", a); }) 84 .map!(a => translate(a, context, Yes.translatingFunction)) 85 ; 86 } 87 88 private auto paramTypes(in from!"clang".Cursor cursor) 89 @safe 90 { 91 import clang: Cursor; 92 import std.algorithm: map, filter; 93 94 return cursor 95 .children 96 .filter!(a => a.kind == Cursor.Kind.ParmDecl) 97 .map!(a => a.type) 98 ; 99 }